Index: vendor/clang/dist/docs/ReleaseNotes.html =================================================================== --- vendor/clang/dist/docs/ReleaseNotes.html (revision 235808) +++ vendor/clang/dist/docs/ReleaseNotes.html (revision 235809) @@ -1,193 +1,193 @@ Clang 3.1 Release Notes

Clang 3.1 Release Notes

LLVM Dragon Logo

Written by the LLVM Team

These are in-progress notes for the upcoming Clang 3.1 release.
You may prefer the Clang 3.0 Release Notes.

Introduction

This document contains the release notes for the Clang C/C++/Objective-C frontend, part of the LLVM Compiler Infrastructure, release 3.1. Here we describe the status of Clang in some detail, including major improvements from the previous release and new feature work. For the general LLVM release notes, see the LLVM documentation. All LLVM releases may be downloaded from the LLVM releases web site.

For more information about Clang or LLVM, including information about the latest release, please check out the main please see the Clang Web Site or the LLVM Web Site.

Note that if you are reading this file from a Subversion checkout or the main Clang web page, this document applies to the next release, not the current one. To see the release notes for a specific release, please see the releases page.

What's New in Clang 3.1?

Some of the major new features and improvements to Clang are listed here. Generic improvements to Clang as a whole or two its underlying infrastructure are described first, followed by language-specific sections with improvements to Clang's support for those languages.

Major New Features

Feature 1

...

New and better diagnostics

New: -Wdangling-else, -Wstrncat-size, ...

Improved: -Wformat, -Wempty-body, -Wliteral-conversion, ...

Tooling

Added an API to enable clang-based standalone tools, including initial build system integration.

C Language Changes in Clang

C11 Feature Support

Clang 3.1 adds support for anonymous structs and anonymous unions, added in the latest ISO C standard. Use -std=c11 or -std=gnu11 to enable support for the new language standard. The new C11 features are backwards-compatible and are available as an extension in all language modes.

All warning and language selection flags which previously accepted c1x have been updated to accept c11. The old c1x forms have been removed.

C++ Language Changes in Clang

C++11 Feature Support

-

Clang 3.1 adds support for -more of the language +

Clang 3.1 supports +most of the language features added in the latest ISO C++ standard, C++ 2011. Use -std=c++11 or -std=gnu++11 to enable support for these features. In addition to the features supported by Clang 3.0, the following are now considered to be of production quality:

Objective-C Language Changes in Clang

Clang 3.1 introduces several new Objective-C language features and improvements.

Format string checking for NSString literals

-Wformat now checks @"nsstring literals".

Internal API Changes

These are major API changes that have happened since the 3.0 release of Clang. If upgrading an external codebase that uses Clang as a library, this section should help get you past the largest hurdles of upgrading.

API change 1

...

Significant Known Problems

Additional Information

A wide variety of additional information is available on the Clang web page. The web page contains versions of the API documentation which are up-to-date with the Subversion version of the source code. You can access versions of these documents specific to this release by going into the "clang/doc/" directory in the Clang tree.

If you have any questions or comments about Clang, please feel free to contact us via the mailing list.

Index: vendor/clang/dist/include/clang/AST/Decl.h =================================================================== --- vendor/clang/dist/include/clang/AST/Decl.h (revision 235808) +++ vendor/clang/dist/include/clang/AST/Decl.h (revision 235809) @@ -1,3342 +1,3339 @@ //===--- 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/Redeclarable.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" #include "clang/Basic/Linkage.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/Compiler.h" namespace clang { class CXXTemporary; class Expr; class FunctionTemplateDecl; class Stmt; class CompoundStmt; class StringLiteral; class NestedNameSpecifier; class TemplateParameterList; class TemplateArgumentList; struct ASTTemplateArgumentListInfo; class MemberSpecializationInfo; class FunctionTemplateSpecializationInfo; class DependentFunctionTemplateSpecializationInfo; class TypeLoc; class UnresolvedSetImpl; class LabelStmt; class Module; /// \brief A container of type source information. /// /// A client can read the relevant info using TypeLoc wrappers, e.g: /// @code /// TypeLoc TL = TypeSourceInfo->getTypeLoc(); /// if (PointerLoc *PL = dyn_cast(&TL)) /// PL->getStarLoc().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) : Decl(TranslationUnit, 0, SourceLocation()), DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(0) {} 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 classof(const TranslationUnitDecl *D) { return true; } 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)); } }; /// 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(); 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(); } void printName(raw_ostream &os) const { return Name.printName(os); } /// 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; } /// getQualifiedNameAsString - 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 getNameAsString(). /// Creating this name is expensive, so it should be called only when /// performance doesn't matter. std::string getQualifiedNameAsString() const; std::string getQualifiedNameAsString(const PrintingPolicy &Policy) const; /// getNameForDiagnostic - Appends a human-readable name for this /// declaration into the given string. /// /// This is the method invoked by Sema when displaying a NamedDecl /// in a diagnostic. It does not necessarily produce the same /// result as getNameAsString(); for example, class template /// specializations are printed with their template arguments. /// /// TODO: use an API that doesn't require so many temporary strings virtual void getNameForDiagnostic(std::string &S, const PrintingPolicy &Policy, bool Qualified) const { if (Qualified) S += getQualifiedNameAsString(Policy); else S += getNameAsString(); } /// declarationReplaces - 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. bool declarationReplaces(NamedDecl *OldD) 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 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. // FIXME: support C++0x scoped enumerations. if (isa(DC)) DC = DC->getParent(); return DC->isRecord(); } /// \brief Determine whether the given declaration is an instance member of /// a C++ class. bool isCXXInstanceMember() const; class LinkageInfo { Linkage linkage_; Visibility visibility_; bool explicit_; public: LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility), explicit_(false) {} LinkageInfo(Linkage L, Visibility V, bool E) : linkage_(L), visibility_(V), explicit_(E) {} static LinkageInfo external() { return LinkageInfo(); } static LinkageInfo internal() { return LinkageInfo(InternalLinkage, DefaultVisibility, false); } static LinkageInfo uniqueExternal() { return LinkageInfo(UniqueExternalLinkage, DefaultVisibility, false); } static LinkageInfo none() { return LinkageInfo(NoLinkage, DefaultVisibility, false); } Linkage linkage() const { return linkage_; } Visibility visibility() const { return visibility_; } bool visibilityExplicit() const { return explicit_; } void setLinkage(Linkage L) { linkage_ = L; } void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; } void mergeLinkage(Linkage L) { setLinkage(minLinkage(linkage(), L)); } void mergeLinkage(LinkageInfo Other) { mergeLinkage(Other.linkage()); } // Merge the visibility V giving preference to explicit ones. // This is used, for example, when merging the visibility of a class // down to one of its members. If the member has no explicit visibility, // the class visibility wins. void mergeVisibility(Visibility V, bool E = false) { // If one has explicit visibility and the other doesn't, keep the // explicit one. if (visibilityExplicit() && !E) return; if (!visibilityExplicit() && E) setVisibility(V, E); // If both are explicit or both are implicit, keep the minimum. setVisibility(minVisibility(visibility(), V), visibilityExplicit() || E); } // Merge the visibility V, keeping the most restrictive one. // This is used for cases like merging the visibility of a template // argument to an instantiation. If we already have a hidden class, // no argument should give it default visibility. void mergeVisibilityWithMin(Visibility V, bool E = false) { // Never increase the visibility if (visibility() < V) return; // If this visibility is explicit, keep it. if (visibilityExplicit() && !E) return; setVisibility(V, E); } void mergeVisibility(LinkageInfo Other) { mergeVisibility(Other.visibility(), Other.visibilityExplicit()); } void mergeVisibilityWithMin(LinkageInfo Other) { mergeVisibilityWithMin(Other.visibility(), Other.visibilityExplicit()); } void merge(LinkageInfo Other) { mergeLinkage(Other); mergeVisibility(Other); } void mergeWithMin(LinkageInfo Other) { mergeLinkage(Other); mergeVisibilityWithMin(Other); } friend LinkageInfo merge(LinkageInfo L, LinkageInfo R) { L.merge(R); return L; } }; /// \brief Determine what kind of linkage this entity has. Linkage getLinkage() const; /// \brief Determines the visibility of this entity. Visibility getVisibility() const { return getLinkageAndVisibility().visibility(); } /// \brief Determines the linkage and visibility of this entity. LinkageInfo getLinkageAndVisibility() const; /// \brief If visibility was explicitly specified for this /// declaration, return that visibility. llvm::Optional getExplicitVisibility() const; /// \brief Clear the linkage cache in response to a change /// to the declaration. void ClearLinkageCache(); /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// the underlying named decl. NamedDecl *getUnderlyingDecl() { // Fast-path the common case. if (this->getKind() != UsingShadow && this->getKind() != ObjCCompatibleAlias) return this; return getUnderlyingDeclImpl(); } const NamedDecl *getUnderlyingDecl() const { return const_cast(this)->getUnderlyingDecl(); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const NamedDecl *D) { return true; } 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 { virtual void anchor(); LabelStmt *TheStmt; /// 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), 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 LLVM_READONLY { return SourceRange(LocStart, getLocation()); } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const LabelDecl *D) { return true; } static bool classofKind(Kind K) { return K == Label; } }; /// NamespaceDecl - Represent a C++ namespace. class NamespaceDecl : public NamedDecl, public DeclContext, public Redeclarable { virtual void anchor(); /// 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(DeclContext *DC, bool Inline, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, NamespaceDecl *PrevDecl); typedef Redeclarable redeclarable_base; virtual NamespaceDecl *getNextRedeclaration() { return RedeclLink.getNext(); } virtual NamespaceDecl *getPreviousDeclImpl() { return getPreviousDecl(); } virtual NamespaceDecl *getMostRecentDeclImpl() { return getMostRecentDecl(); } 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_iterator redecl_iterator; using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::getPreviousDecl; using redeclarable_base::getMostRecentDecl; /// \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() { if (isFirstDeclaration()) return this; return AnonOrFirstNamespaceAndInline.getPointer(); } /// \brief Get the original (first) namespace declaration. const NamespaceDecl *getOriginalNamespace() const { if (isFirstDeclaration()) return this; return AnonOrFirstNamespaceAndInline.getPointer(); } /// \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 { return isFirstDeclaration(); } /// \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() { return getOriginalNamespace(); } const NamespaceDecl *getCanonicalDecl() const { return getOriginalNamespace(); } virtual SourceRange getSourceRange() const 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 classof(const NamespaceDecl *D) { return true; } 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 { virtual void anchor(); 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 { return hasAttr() || hasAttr() || isWeakImported(); } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ValueDecl *D) { return true; } 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(0) {} /// setTemplateParameterListsInfo - Sets info about "outer" template /// parameter lists. void setTemplateParameterListsInfo(ASTContext &Context, unsigned NumTPLists, TemplateParameterList **TPLists); private: // Copy constructor and copy assignment are disabled. QualifierInfo(const QualifierInfo&); QualifierInfo& operator=(const QualifierInfo&); }; /// \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; virtual SourceRange getSourceRange() const 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() : 0; } /// \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, unsigned NumTPLists, TemplateParameterList **TPLists); SourceLocation getTypeSpecStartLoc() const; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const DeclaratorDecl *D) { return true; } 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: typedef clang::StorageClass StorageClass; /// getStorageClassSpecifierString - Return the string used to /// specify the storage class \arg 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) }; protected: /// \brief Placeholder type used in Init to denote an unparsed C++ default /// argument. struct UnparsedDefaultArgument; /// \brief Placeholder type used in Init to denote an uninstantiated C++ /// default argument. struct UninstantiatedDefaultArgument; typedef llvm::PointerUnion4 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 SClassAsWritten : 3; unsigned ThreadSpecified : 1; unsigned InitStyle : 2; /// \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++0x) constexpr. unsigned IsConstexpr : 1; }; enum { NumVarDeclBits = 14 }; friend class ASTDeclReader; friend class StmtIteratorBase; protected: enum { NumParameterIndexBits = 8 }; class ParmVarDeclBitfields { friend class ParmVarDecl; friend class ASTDeclReader; unsigned : NumVarDeclBits; /// Whether this parameter inherits a default argument from a /// prior declaration. unsigned HasInheritedDefaultArg : 1; /// 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; }; union { unsigned AllBits; VarDeclBitfields VarDeclBits; ParmVarDeclBitfields ParmVarDeclBits; }; VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass SC, StorageClass SCAsWritten) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() { assert(sizeof(VarDeclBitfields) <= sizeof(unsigned)); assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned)); AllBits = 0; VarDeclBits.SClass = SC; VarDeclBits.SClassAsWritten = SCAsWritten; // Everything else is implicitly initialized to false. } typedef Redeclarable redeclarable_base; virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); } virtual VarDecl *getPreviousDeclImpl() { return getPreviousDecl(); } virtual VarDecl *getMostRecentDeclImpl() { return getMostRecentDecl(); } public: typedef redeclarable_base::redecl_iterator redecl_iterator; using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::getPreviousDecl; using redeclarable_base::getMostRecentDecl; static VarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, StorageClass SCAsWritten); static VarDecl *CreateDeserialized(ASTContext &C, unsigned ID); virtual SourceRange getSourceRange() const LLVM_READONLY; StorageClass getStorageClass() const { return (StorageClass) VarDeclBits.SClass; } StorageClass getStorageClassAsWritten() const { return (StorageClass) VarDeclBits.SClassAsWritten; } void setStorageClass(StorageClass SC); void setStorageClassAsWritten(StorageClass SC) { assert(isLegalForVariable(SC)); VarDeclBits.SClassAsWritten = SC; } void setThreadSpecified(bool T) { VarDeclBits.ThreadSpecified = T; } bool isThreadSpecified() const { return VarDeclBits.ThreadSpecified; } /// hasLocalStorage - Returns true if a variable with function scope /// is a non-static local variable. bool hasLocalStorage() const { if (getStorageClass() == SC_None) return !isFileVarDecl(); // 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 && !isFileVarDecl(); } /// hasExternStorage - Returns true if a variable has extern or /// __private_extern__ storage. bool hasExternalStorage() const { return getStorageClass() == SC_Extern || getStorageClass() == SC_PrivateExtern; } /// hasGlobalStorage - Returns true for all variables that do not /// have local storage. This includs all global variables as well /// as static variables declared within a function. bool hasGlobalStorage() const { return !hasLocalStorage(); } /// \brief Determines whether this variable is a variable with /// external, C linkage. bool isExternC() 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) return false; if (const DeclContext *DC = getDeclContext()) return DC->getRedeclContext()->isFunctionOrMethod(); return false; } /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but /// excludes variables declared in blocks. bool isFunctionOrMethodVarDecl() const { if (getKind() != Decl::Var) return false; const DeclContext *DC = getDeclContext()->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(); } virtual VarDecl *getCanonicalDecl(); 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 Determine whether this is a tentative definition of a /// variable in C. bool isTentativeDefinitionNow() const; /// \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. virtual bool isOutOfLine() const; /// \brief If this is a static data member, find its out-of-line definition. VarDecl *getOutOfLineDefinition(); /// isFileVarDecl - Returns true for file scoped variable declaration. bool isFileVarDecl() const { if (getKind() != Decl::Var) return false; if (getDeclContext()->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 { return !Init.isNull() && (Init.is() || Init.is()); } const Expr *getInit() const { if (Init.isNull()) return 0; const Stmt *S = Init.dyn_cast(); if (!S) { if (EvaluatedStmt *ES = Init.dyn_cast()) S = ES->Value; } return (const Expr*) S; } Expr *getInit() { if (Init.isNull()) return 0; Stmt *S = Init.dyn_cast(); if (!S) { if (EvaluatedStmt *ES = Init.dyn_cast()) S = ES->Value; } return (Expr*) S; } /// \brief Retrieve the address of the initializer expression. Stmt **getInitAddress() { if (EvaluatedStmt *ES = Init.dyn_cast()) return &ES->Value; // This union hack tip-toes around strict-aliasing rules. union { InitType *InitPtr; Stmt **StmtPtr; }; InitPtr = &Init; return StmtPtr; } void setInit(Expr *I); /// \brief Determine whether this variable is a reference that /// extends the lifetime of its temporary initializer. /// /// A reference extends the lifetime of its temporary initializer if /// it's initializer is an rvalue that would normally go out of scope /// at the end of the initializer (a full expression). In such cases, /// the reference itself takes ownership of the temporary, which will /// be destroyed when the reference goes out of scope. For example: /// /// \code /// const int &r = 1.0; // creates a temporary of type 'int' /// \endcode bool extendsLifetimeOfTemporary() const; /// \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( llvm::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 { if (EvaluatedStmt *Eval = Init.dyn_cast()) if (Eval->WasEvaluated) return &Eval->Evaluated; return 0; } /// \brief Determines whether it is already known whether the /// initializer is an integral constant expression or not. bool isInitKnownICE() const { if (EvaluatedStmt *Eval = Init.dyn_cast()) return Eval->CheckedICE; return false; } /// \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 { assert(isInitKnownICE() && "Check whether we already know that the initializer is an ICE"); return Init.get()->IsICE; } /// \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 Determine whether this variable is the exception variable in a /// C++ catch statememt or an Objective-C @catch statement. bool isExceptionVariable() const { return VarDeclBits.ExceptionVar; } void setExceptionVariable(bool EV) { VarDeclBits.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 VarDeclBits.NRVOVariable; } void setNRVOVariable(bool NRVO) { VarDeclBits.NRVOVariable = NRVO; } /// \brief Determine whether this variable is the for-range-declaration in /// a C++0x for-range statement. bool isCXXForRangeDecl() const { return VarDeclBits.CXXForRangeDecl; } void setCXXForRangeDecl(bool FRD) { VarDeclBits.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 VarDeclBits.ARCPseudoStrong; } void setARCPseudoStrong(bool ps) { VarDeclBits.ARCPseudoStrong = ps; } /// Whether this variable is (C++0x) constexpr. bool isConstexpr() const { return VarDeclBits.IsConstexpr; } void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; } /// \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 a static data member, determine what kind of /// template specialization or instantiation this is. TemplateSpecializationKind getTemplateSpecializationKind() 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()); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const VarDecl *D) { return true; } static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; } }; class ImplicitParamDecl : public VarDecl { virtual void anchor(); public: static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, QualType T); static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID); ImplicitParamDecl(DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, QualType Type) : VarDecl(ImplicitParam, DC, IdLoc, IdLoc, Id, Type, /*tinfo*/ 0, SC_None, SC_None) { setImplicit(); } // Implement isa/cast/dyncast/etc. static bool classof(const ImplicitParamDecl *D) { return true; } 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, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, StorageClass SCAsWritten, Expr *DefArg) : VarDecl(DK, DC, StartLoc, IdLoc, Id, T, TInfo, S, SCAsWritten) { assert(ParmVarDeclBits.HasInheritedDefaultArg == false); 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, StorageClass SCAsWritten, Expr *DefArg); static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID); virtual SourceRange getSourceRange() const 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) { Init = reinterpret_cast(defarg); } /// \brief Retrieve the source range that covers the entire default /// argument. SourceRange getDefaultArgRange() const; void setUninstantiatedDefaultArg(Expr *arg) { Init = reinterpret_cast(arg); } Expr *getUninstantiatedDefaultArg() { return (Expr *)Init.get(); } const Expr *getUninstantiatedDefaultArg() const { return (const Expr *)Init.get(); } /// hasDefaultArg - Determines whether this parameter has a default argument, /// either parsed or not. bool hasDefaultArg() const { return getInit() || hasUnparsedDefaultArg() || hasUninstantiatedDefaultArg(); } /// 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 Init.is(); } bool hasUninstantiatedDefaultArg() const { return Init.is(); } /// 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() { Init = (UnparsedDefaultArgument *)0; } bool hasInheritedDefaultArg() const { return ParmVarDeclBits.HasInheritedDefaultArg; } void setHasInheritedDefaultArg(bool I = true) { ParmVarDeclBits.HasInheritedDefaultArg = I; } QualType getOriginalType() const { if (getTypeSourceInfo()) return getTypeSourceInfo()->getType(); return getType(); } /// \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 classof(const ParmVarDecl *D) { return true; } 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: typedef clang::StorageClass StorageClass; /// \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; /// DeclsInPrototypeScope - Array of pointers to NamedDecls for /// decls defined in the function prototype that are not parameters. E.g. /// 'enum Y' in 'void f(enum Y {AA} x) {}'. llvm::ArrayRef DeclsInPrototypeScope; LazyDeclStmtPtr Body; // FIXME: This can be packed into the bitfields in Decl. // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum unsigned SClass : 2; unsigned SClassAsWritten : 2; bool IsInline : 1; bool IsInlineSpecified : 1; bool IsVirtualAsWritten : 1; bool IsPure : 1; bool HasInheritedPrototype : 1; bool HasWrittenPrototype : 1; bool IsDeleted : 1; bool IsTrivial : 1; // sunk from CXXMethodDecl bool IsDefaulted : 1; // sunk from CXXMethoDecl bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl bool HasImplicitReturnZero : 1; bool IsLateTemplateParsed : 1; bool IsConstexpr : 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, llvm::ArrayRef NewParamInfo); protected: FunctionDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, StorageClass SCAsWritten, bool isInlineSpecified, bool isConstexprSpecified) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, StartLoc), DeclContext(DK), ParamInfo(0), Body(), SClass(S), SClassAsWritten(SCAsWritten), IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified), IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), IsDefaulted(false), IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), DNLoc(NameInfo.getInfo()) {} typedef Redeclarable redeclarable_base; virtual FunctionDecl *getNextRedeclaration() { return RedeclLink.getNext(); } virtual FunctionDecl *getPreviousDeclImpl() { return getPreviousDecl(); } virtual FunctionDecl *getMostRecentDeclImpl() { return getMostRecentDecl(); } public: typedef redeclarable_base::redecl_iterator redecl_iterator; using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::getPreviousDecl; using redeclarable_base::getMostRecentDecl; static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation NLoc, DeclarationName N, QualType T, TypeSourceInfo *TInfo, StorageClass SC = SC_None, StorageClass SCAsWritten = SC_None, bool isInlineSpecified = false, bool hasWrittenPrototype = true, bool isConstexprSpecified = false) { DeclarationNameInfo NameInfo(N, NLoc); return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC, SCAsWritten, isInlineSpecified, hasWrittenPrototype, isConstexprSpecified); } static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass SC = SC_None, StorageClass SCAsWritten = SC_None, bool isInlineSpecified = false, bool hasWrittenPrototype = true, bool isConstexprSpecified = false); static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID); DeclarationNameInfo getNameInfo() const { return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); } virtual void getNameForDiagnostic(std::string &S, const PrintingPolicy &Policy, bool Qualified) const; void setRangeEnd(SourceLocation E) { EndRangeLoc = E; } virtual SourceRange getSourceRange() const 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; virtual bool hasBody() const { 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); } /// 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; virtual Stmt *getBody() const { 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++0x) constexpr function or constexpr constructor. bool isConstexpr() const { return IsConstexpr; } void setConstexpr(bool IC) { IsConstexpr = IC; } /// \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 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 a function with /// external, C linkage. bool isExternC() const; /// \brief Determines whether this is a global function. bool isGlobal() const; void setPreviousDeclaration(FunctionDecl * PrevDecl); virtual const FunctionDecl *getCanonicalDecl() const; virtual FunctionDecl *getCanonicalDecl(); unsigned getBuiltinID() const; // Iterator access to formal parameters. unsigned param_size() const { return getNumParams(); } typedef ParmVarDecl **param_iterator; typedef ParmVarDecl * const *param_const_iterator; param_iterator param_begin() { return ParamInfo; } param_iterator param_end() { return ParamInfo+param_size(); } param_const_iterator param_begin() const { return ParamInfo; } param_const_iterator param_end() const { return ParamInfo+param_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(llvm::ArrayRef NewParamInfo) { setParams(getASTContext(), NewParamInfo); } const llvm::ArrayRef &getDeclsInPrototypeScope() const { return DeclsInPrototypeScope; } void setDeclsInPrototypeScope(llvm::ArrayRef NewDecls); /// 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 getResultType() const { return getType()->getAs()->getResultType(); } /// \brief Determine the type of an expression that calls this function. QualType getCallResultType() const { return getType()->getAs()->getCallResultType(getASTContext()); } StorageClass getStorageClass() const { return StorageClass(SClass); } void setStorageClass(StorageClass SC); StorageClass getStorageClassAsWritten() const { return StorageClass(SClassAsWritten); } /// \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; bool isInlineDefinitionExternallyVisible() 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 { return TemplateOrSpecialization.dyn_cast(); } void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { TemplateOrSpecialization = Template; } /// \brief Determine whether this function is a function template /// specialization. bool isFunctionTemplateSpecialization() const { return getPrimaryTemplate() != 0; } /// \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 { return TemplateOrSpecialization. dyn_cast(); } /// \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 = 0, 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 { return TemplateOrSpecialization. dyn_cast(); } /// \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. virtual bool isOutOfLine() const; /// \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 classof(const FunctionDecl *D) { return true; } 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 { // FIXME: This can be packed into the bitfields in Decl. bool Mutable : 1; mutable unsigned CachedFieldIndex : 31; /// \brief A pointer to either the in-class initializer for this field (if /// the boolean value is false), or the bit width expression for this bit /// field (if the boolean value is true). /// /// We can safely combine these two because in-class initializers are not /// permitted for bit-fields. /// /// If the boolean is false and the initializer is null, then this field has /// an in-class initializer which has not yet been parsed and attached. llvm::PointerIntPair InitializerOrBitWidth; protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, bool HasInit) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Mutable(Mutable), CachedFieldIndex(0), InitializerOrBitWidth(BW, !HasInit) { assert(!(BW && HasInit) && "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, bool HasInit); 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 Set whether this field is mutable (C++ only). void setMutable(bool M) { Mutable = M; } /// isBitfield - Determines whether this field is a bitfield. bool isBitField() const { return InitializerOrBitWidth.getInt() && InitializerOrBitWidth.getPointer(); } /// @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() ? InitializerOrBitWidth.getPointer() : 0; } unsigned getBitWidthValue(const ASTContext &Ctx) const; void setBitWidth(Expr *BW) { assert(!InitializerOrBitWidth.getPointer() && "bit width or initializer already set"); InitializerOrBitWidth.setPointer(BW); InitializerOrBitWidth.setInt(1); } /// removeBitWidth - Remove the bitfield width from this member. void removeBitWidth() { assert(isBitField() && "no bit width to remove"); InitializerOrBitWidth.setPointer(0); } /// hasInClassInitializer - Determine whether this member has a C++0x in-class /// initializer. bool hasInClassInitializer() const { return !InitializerOrBitWidth.getInt(); } /// getInClassInitializer - Get the C++0x 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() ? InitializerOrBitWidth.getPointer() : 0; } /// setInClassInitializer - Set the C++0x in-class initializer for this /// member. void setInClassInitializer(Expr *Init); /// removeInClassInitializer - Remove the C++0x in-class initializer from this /// member. void removeInClassInitializer() { assert(!InitializerOrBitWidth.getInt() && "no initializer to remove"); InitializerOrBitWidth.setPointer(0); InitializerOrBitWidth.setInt(1); } /// getParent - Returns the parent of this field declaration, which /// is the struct in which this method is defined. const RecordDecl *getParent() const { return cast(getDeclContext()); } RecordDecl *getParent() { return cast(getDeclContext()); } SourceRange getSourceRange() const LLVM_READONLY; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const FieldDecl *D) { return true; } static bool classofKind(Kind K) { return K >= firstField && K <= lastField; } }; /// 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 { 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 LLVM_READONLY; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const EnumConstantDecl *D) { return true; } 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 { virtual void anchor(); NamedDecl **Chaining; unsigned ChainingSize; IndirectFieldDecl(DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, NamedDecl **CH, unsigned CHS) : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {} public: static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, NamedDecl **CH, unsigned CHS); static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); typedef NamedDecl * const *chain_iterator; chain_iterator chain_begin() const { return Chaining; } chain_iterator chain_end() const { return Chaining+ChainingSize; } unsigned getChainingSize() const { return ChainingSize; } FieldDecl *getAnonField() const { assert(ChainingSize >= 2); return cast(Chaining[ChainingSize - 1]); } VarDecl *getVarDecl() const { assert(ChainingSize >= 2); return dyn_cast(*chain_begin()); } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const IndirectFieldDecl *D) { return true; } static bool classofKind(Kind K) { return K == IndirectField; } friend class ASTDeclReader; }; /// TypeDecl - Represents a declaration of a type. /// class TypeDecl : public NamedDecl { virtual void anchor(); /// 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; friend class DeclContext; friend class TagDecl; friend class TemplateTypeParmDecl; friend class TagType; friend class ASTReader; protected: TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation StartL = SourceLocation()) : NamedDecl(DK, DC, L, Id), TypeForDecl(0), LocStart(StartL) {} public: // Low-level accessor 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; } virtual SourceRange getSourceRange() const 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 classof(const TypeDecl *D) { return true; } 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 { virtual void anchor(); /// UnderlyingType - This is the type the typedef is set to. TypeSourceInfo *TInfo; protected: TypedefNameDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) : TypeDecl(DK, DC, IdLoc, Id, StartLoc), TInfo(TInfo) {} typedef Redeclarable redeclarable_base; virtual TypedefNameDecl *getNextRedeclaration() { return RedeclLink.getNext(); } virtual TypedefNameDecl *getPreviousDeclImpl() { return getPreviousDecl(); } virtual TypedefNameDecl *getMostRecentDeclImpl() { return getMostRecentDecl(); } public: typedef redeclarable_base::redecl_iterator redecl_iterator; using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::getPreviousDecl; using redeclarable_base::getMostRecentDecl; TypeSourceInfo *getTypeSourceInfo() const { return TInfo; } /// Retrieves the canonical declaration of this typedef-name. TypedefNameDecl *getCanonicalDecl() { return getFirstDeclaration(); } const TypedefNameDecl *getCanonicalDecl() const { return getFirstDeclaration(); } QualType getUnderlyingType() const { return TInfo->getType(); } void setTypeSourceInfo(TypeSourceInfo *newType) { TInfo = newType; } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TypedefNameDecl *D) { return true; } static bool classofKind(Kind K) { return K >= firstTypedefName && K <= lastTypedefName; } }; /// TypedefDecl - Represents the declaration of a typedef-name via the 'typedef' /// type specifier. class TypedefDecl : public TypedefNameDecl { TypedefDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) : TypedefNameDecl(Typedef, 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 LLVM_READONLY; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TypedefDecl *D) { return true; } 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 { TypeAliasDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) : TypedefNameDecl(TypeAlias, DC, StartLoc, IdLoc, Id, TInfo) {} 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 LLVM_READONLY; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TypeAliasDecl *D) { return true; } 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 : 2; /// 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. bool IsCompleteDefinition : 1; protected: /// IsBeingDefined - True if this is currently being defined. bool 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. bool IsEmbeddedInDeclarator : 1; /// \brief True if this tag is free standing, e.g. "struct foo;". bool 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. bool 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. bool IsScopedUsingClassTag : 1; /// IsFixed - True if this is an enumeration with fixed underlying type. Only /// possible in C++11 or Microsoft extensions mode. bool IsFixed : 1; private: SourceLocation RBraceLoc; // A struct representing syntactic qualifier info, // to be used for the (uncommon) case of out-of-line declarations. typedef QualifierInfo ExtInfo; /// TypedefNameDeclOrQualifier - 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, 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, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, TagDecl *PrevDecl, SourceLocation StartL) : TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), TypedefNameDeclOrQualifier((TypedefNameDecl*) 0) { assert((DK != Enum || TK == TTK_Enum) && "EnumDecl not matched with TTK_Enum"); TagDeclKind = TK; IsCompleteDefinition = false; IsBeingDefined = false; IsEmbeddedInDeclarator = false; IsFreeStanding = false; setPreviousDeclaration(PrevDecl); } typedef Redeclarable redeclarable_base; virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); } virtual TagDecl *getPreviousDeclImpl() { return getPreviousDecl(); } virtual TagDecl *getMostRecentDeclImpl() { 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_iterator redecl_iterator; using redeclarable_base::redecls_begin; using redeclarable_base::redecls_end; using redeclarable_base::getPreviousDecl; using redeclarable_base::getMostRecentDecl; SourceLocation getRBraceLoc() const { return RBraceLoc; } void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } /// 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; virtual SourceRange getSourceRange() const LLVM_READONLY; virtual TagDecl* getCanonicalDecl(); const TagDecl* getCanonicalDecl() const { return const_cast(this)->getCanonicalDecl(); } /// isThisDeclarationADefinition() - Return true if this declaration /// is a completion definintion 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; } /// 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; } const char *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 isClass() const { return getTagKind() == TTK_Class; } bool isUnion() const { return getTagKind() == TTK_Union; } bool isEnum() const { return getTagKind() == TTK_Enum; } TypedefNameDecl *getTypedefNameForAnonDecl() const { return hasExtInfo() ? 0 : 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() : 0; } /// \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, unsigned NumTPLists, TemplateParameterList **TPLists); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TagDecl *D) { return true; } 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 { virtual void anchor(); /// 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(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, EnumDecl *PrevDecl, bool Scoped, bool ScopedUsingClassTag, bool Fixed) : TagDecl(Enum, TTK_Enum, DC, IdLoc, Id, PrevDecl, StartLoc), SpecializationInfo(0) { assert(Scoped || !ScopedUsingClassTag); IntegerType = (const Type*)0; NumNegativeBits = 0; NumPositiveBits = 0; IsScoped = Scoped; IsScopedUsingClassTag = ScopedUsingClassTag; IsFixed = Fixed; } void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED, TemplateSpecializationKind TSK); public: EnumDecl *getCanonicalDecl() { return cast(TagDecl::getCanonicalDecl()); } const EnumDecl *getCanonicalDecl() const { return cast(TagDecl::getCanonicalDecl()); } const EnumDecl *getPreviousDecl() const { return cast_or_null(TagDecl::getPreviousDecl()); } EnumDecl *getPreviousDecl() { return cast_or_null(TagDecl::getPreviousDecl()); } const EnumDecl *getMostRecentDecl() const { return cast(TagDecl::getMostRecentDecl()); } EnumDecl *getMostRecentDecl() { return cast(TagDecl::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; 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. QualType getIntegerType() const { if (!IntegerType) return QualType(); if (const Type* T = IntegerType.dyn_cast()) return QualType(T, 0); return IntegerType.get()->getType(); } /// \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 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++0x scoped enumeration. bool isScoped() const { return IsScoped; } /// \brief Returns true if this is a C++0x scoped enumeration. bool isScopedUsingClassTag() const { return IsScopedUsingClassTag; } /// \brief Returns true if this is a C++0x enumeration with 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(); } /// \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 classof(const EnumDecl *D) { return true; } 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; /// \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, 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 = 0); static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); const RecordDecl *getPreviousDecl() const { return cast_or_null(TagDecl::getPreviousDecl()); } RecordDecl *getPreviousDecl() { return cast_or_null(TagDecl::getPreviousDecl()); } const RecordDecl *getMostRecentDecl() const { return cast(TagDecl::getMostRecentDecl()); } RecordDecl *getMostRecentDecl() { return cast(TagDecl::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; } /// \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; /// 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; 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 classof(const RecordDecl *D) { return true; } static bool classofKind(Kind K) { return K >= firstRecord && K <= lastRecord; } 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 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 classof(const FileScopeAsmDecl *D) { return true; } 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 != 0; } 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; Capture *Captures; unsigned NumCaptures; protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) : Decl(Block, DC, CaretLoc), DeclContext(Block), IsVariadic(false), CapturesCXXThis(false), BlockMissingReturnType(true), IsConversionFromLambda(false), ParamInfo(0), NumParams(0), Body(0), SignatureAsWritten(0), Captures(0), NumCaptures(0) {} 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 { return (Stmt*) Body; } void setBody(CompoundStmt *B) { Body = (Stmt*) B; } void setSignatureAsWritten(TypeSourceInfo *Sig) { SignatureAsWritten = Sig; } TypeSourceInfo *getSignatureAsWritten() const { return SignatureAsWritten; } // Iterator access to formal parameters. unsigned param_size() const { return getNumParams(); } typedef ParmVarDecl **param_iterator; typedef ParmVarDecl * const *param_const_iterator; bool param_empty() const { return NumParams == 0; } param_iterator param_begin() { return ParamInfo; } param_iterator param_end() { return ParamInfo+param_size(); } param_const_iterator param_begin() const { return ParamInfo; } param_const_iterator param_end() const { return ParamInfo+param_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(llvm::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 const Capture *capture_iterator; typedef const Capture *capture_const_iterator; capture_iterator capture_begin() { return Captures; } capture_iterator capture_end() { return Captures + NumCaptures; } capture_const_iterator capture_begin() const { return Captures; } capture_const_iterator capture_end() const { return Captures + NumCaptures; } 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, const Capture *begin, const Capture *end, bool capturesCXXThis); virtual SourceRange getSourceRange() const LLVM_READONLY; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const BlockDecl *D) { return true; } 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 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 /// @__experimental_modules_import std.vector; /// \endcode /// /// Import declarations can also be implicitly generated from #include/#import /// directives. class ImportDecl : public Decl { /// \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; 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; virtual SourceRange getSourceRange() const LLVM_READONLY; static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ImportDecl *D) { return true; } static bool classofKind(Kind K) { return K == Import; } }; /// 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::setPreviousDeclaration(decl_type *PrevDecl) { // Note: This routine is implemented here because we need both NamedDecl // and Redeclarable to be defined. decl_type *First; 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. RedeclLink = PreviousDeclLink( llvm::cast(PrevDecl->getMostRecentDecl())); First = PrevDecl->getFirstDeclaration(); assert(First->RedeclLink.NextIsLatest() && "Expected first"); } else { // Make this first. First = static_cast(this); } // First one will point to this one as latest. First->RedeclLink = LatestDeclLink(static_cast(this)); if (NamedDecl *ND = dyn_cast(static_cast(this))) ND->ClearLinkageCache(); } // 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/Basic/DiagnosticParseKinds.td =================================================================== --- vendor/clang/dist/include/clang/Basic/DiagnosticParseKinds.td (revision 235808) +++ vendor/clang/dist/include/clang/Basic/DiagnosticParseKinds.td (revision 235809) @@ -1,720 +1,718 @@ //==--- DiagnosticParseKinds.td - libparse diagnostics --------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Parser Diagnostics //===----------------------------------------------------------------------===// let Component = "Parse" in { def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">, CatInlineAsm; def warn_file_asm_volatile : Warning< "meaningless 'volatile' on asm outside function">, CatInlineAsm; let CategoryName = "Parse Issue" in { def ext_empty_source_file : Extension<"ISO C forbids an empty source file">; def ext_top_level_semi : Extension< "extra ';' outside of a function">; def warn_cxx98_compat_top_level_semi : Warning< "extra ';' outside of a function is incompatible with C++98">, InGroup, DefaultIgnore; def ext_extra_struct_semi : Extension< "extra ';' inside a %0">; def ext_extra_ivar_semi : Extension< "extra ';' inside instance variable list">; def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">; def ext_plain_complex : ExtWarn< "plain '_Complex' requires a type specifier; assuming '_Complex double'">; def ext_integer_complex : Extension< "complex integer types are an extension">; def ext_thread_before : Extension<"'__thread' before 'static'">; def ext_empty_struct_union : Extension< "empty %select{struct|union}0 is a GNU extension">, InGroup; def warn_empty_struct_union_compat : Warning<"empty %select{struct|union}0 " "has size 0 in C, size 1 in C++">, InGroup, DefaultIgnore; def error_empty_enum : Error<"use of empty enum">; def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">; def err_invalid_short_spec : Error<"'short %0' is invalid">; def err_invalid_long_spec : Error<"'long %0' is invalid">; def err_invalid_longlong_spec : Error<"'long long %0' is invalid">; def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">; def err_friend_storage_spec : Error<"'%0' is invalid in friend declarations">; def ext_ident_list_in_param : Extension< "type-less parameter names in function declaration">; def ext_c99_variable_decl_in_for_loop : Extension< "variable declaration in for loop is a C99-specific feature">, InGroup; def ext_c99_compound_literal : Extension< "compound literals are a C99-specific feature">, InGroup; def ext_c99_flexible_array_member : Extension< "Flexible array members are a C99-specific feature">, InGroup; def ext_enumerator_list_comma : Extension< "commas at the end of enumerator lists are a %select{C99|C++11}0-specific " "feature">; def warn_cxx98_compat_enumerator_list_comma : Warning< "commas at the end of enumerator lists are incompatible with C++98">, InGroup, DefaultIgnore; def err_enumerator_list_missing_comma : Error< "missing ',' between enumerators">; def err_enumerator_unnamed_no_def : Error< "unnamed enumeration must be a definition">; def ext_ms_enum_fixed_underlying_type : Extension< "enumeration types with a fixed underlying type are a Microsoft extension">, InGroup; def warn_cxx98_compat_enum_fixed_underlying_type : Warning< "enumeration types with a fixed underlying type are incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_alignof : Warning< "alignof expressions are incompatible with C++98">, InGroup, DefaultIgnore; def warn_microsoft_dependent_exists : Warning< "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">, InGroup>; def ext_c11_generic_selection : Extension< "generic selections are a C11-specific feature">, InGroup; def err_duplicate_default_assoc : Error< "duplicate default generic association">; def note_previous_default_assoc : Note< "previous default generic association is here">; def ext_c11_alignas : Extension< "_Alignas is a C11-specific feature">, InGroup; def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">, InGroup; def ext_gnu_address_of_label : Extension< "use of GNU address-of-label extension">, InGroup; def ext_gnu_local_label : Extension< "use of GNU locally declared label extension">, InGroup; def ext_gnu_statement_expr : Extension< "use of GNU statement expression extension">, InGroup; def ext_gnu_conditional_expr : Extension< "use of GNU ?: expression extension, eliding middle term">, InGroup; def ext_gnu_empty_initializer : Extension< "use of GNU empty initializer extension">, InGroup; def ext_gnu_array_range : Extension<"use of GNU array range extension">, InGroup; def ext_gnu_missing_equal_designator : ExtWarn< "use of GNU 'missing =' extension in designator">, InGroup; def err_expected_equal_designator : Error<"expected '=' or another designator">; def ext_gnu_old_style_field_designator : ExtWarn< "use of GNU old-style field designator extension">, InGroup; def ext_gnu_case_range : Extension<"use of GNU case range extension">, InGroup; // Generic errors. def err_expected_expression : Error<"expected expression">; def err_expected_type : Error<"expected a type">; def err_expected_external_declaration : Error<"expected external declaration">; def err_extraneous_closing_brace : Error<"extraneous closing brace ('}')">; def err_expected_ident : Error<"expected identifier">; def err_expected_ident_lparen : Error<"expected identifier or '('">; def err_expected_ident_lbrace : Error<"expected identifier or '{'">; def err_expected_lbrace : Error<"expected '{'">; def err_expected_lparen : Error<"expected '('">; def err_expected_lparen_or_lbrace : Error<"expected '('or '{'">; def err_expected_rparen : Error<"expected ')'">; def err_expected_lsquare : Error<"expected '['">; def err_expected_rsquare : Error<"expected ']'">; def err_expected_rbrace : Error<"expected '}'">; def err_expected_greater : Error<"expected '>'">; def err_expected_ggg : Error<"expected '>>>'">; def err_expected_semi_declaration : Error< "expected ';' at end of declaration">; def err_expected_semi_decl_list : Error< "expected ';' at end of declaration list">; def ext_expected_semi_decl_list : ExtWarn< "expected ';' at end of declaration list">; def err_expected_member_name_or_semi : Error< "expected member name or ';' after declaration specifiers">; def err_function_declared_typedef : Error< "function definition declared 'typedef'">; def err_iboutletcollection_builtintype : Error< "type argument of iboutletcollection attribute cannot be a builtin type">; def err_iboutletcollection_with_protocol : Error< "invalid argument of iboutletcollection attribute">; def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">; def err_at_in_class : Error<"unexpected '@' in member specification">; def err_expected_fn_body : Error< "expected function body after function declarator">; def warn_attribute_on_function_definition : Warning< "GCC does not allow %0 attribute in this position on a function definition">, InGroup; def warn_attribute_no_decl : Warning< "attribute %0 ignored, because it is not attached to a declaration">, InGroup; def err_expected_method_body : Error<"expected method body">; def err_invalid_token_after_toplevel_declarator : Error< "expected ';' after top level declarator">; def err_invalid_token_after_declarator_suggest_equal : Error< "invalid '%0' at end of declaration; did you mean '='?">; def err_expected_statement : Error<"expected statement">; def err_expected_lparen_after : Error<"expected '(' after '%0'">; def err_expected_lparen_after_id : Error<"expected '(' after %0">; def err_expected_less_after : Error<"expected '<' after '%0'">; def err_expected_equal_after : Error<"expected '=' after %0">; def err_expected_comma : Error<"expected ','">; def err_expected_lbrace_in_compound_literal : Error< "expected '{' in compound literal">; def err_expected_while : Error<"expected 'while' in do/while loop">; def err_expected_semi_after : Error<"expected ';' after %0">; def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">; def err_expected_semi_after_expr : Error<"expected ';' after expression">; def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">; def err_expected_semi_after_method_proto : Error< "expected ';' after method prototype">; def err_expected_semi_after_namespace_name : Error< "expected ';' after namespace name">; def err_unexpected_namespace_attributes_alias : Error< "attributes can not be specified on namespace alias">; def err_inline_namespace_alias : Error<"namespace alias cannot be inline">; def err_namespace_nonnamespace_scope : Error< "namespaces can only be defined in global or namespace scope">; def err_nested_namespaces_with_double_colon : Error< "nested namespace definition must define each namespace separately">; def err_expected_semi_after_attribute_list : Error< "expected ';' after attribute list">; def err_expected_semi_after_static_assert : Error< "expected ';' after static_assert">; def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">; def err_expected_colon_after : Error<"expected ':' after %0">; def err_label_end_of_compound_statement : Error< "label at end of compound statement: expected statement">; def err_address_of_label_outside_fn : Error< "use of address-of-label extension outside of a function body">; def err_expected_string_literal : Error<"expected string literal">; def err_asm_operand_wide_string_literal : Error< "cannot use %select{unicode|wide}0 string literal in 'asm'">; def err_expected_selector_for_method : Error< "expected selector for Objective-C method">; def err_expected_property_name : Error<"expected property name">; def err_unexpected_at : Error<"unexpected '@' in program">; def err_invalid_reference_qualifier_application : Error< "'%0' qualifier may not be applied to a reference">; def err_illegal_decl_reference_to_reference : Error< "%0 declared as a reference to a reference">; def ext_rvalue_reference : ExtWarn< "rvalue references are a C++11 extension">, InGroup; def warn_cxx98_compat_rvalue_reference : Warning< "rvalue references are incompatible with C++98">, InGroup, DefaultIgnore; def ext_ref_qualifier : ExtWarn< "reference qualifiers on functions are a C++11 extension">, InGroup; def warn_cxx98_compat_ref_qualifier : Warning< "reference qualifiers on functions are incompatible with C++98">, InGroup, DefaultIgnore; def ext_inline_namespace : ExtWarn< "inline namespaces are a C++11 feature">, InGroup; def warn_cxx98_compat_inline_namespace : Warning< "inline namespaces are incompatible with C++98">, InGroup, DefaultIgnore; def ext_generalized_initializer_lists : ExtWarn< "generalized initializer lists are a C++11 extension">, InGroup; def warn_cxx98_compat_generalized_initializer_lists : Warning< "generalized initializer lists are incompatible with C++98">, InGroup, DefaultIgnore; def err_init_list_bin_op : Error<"initializer list cannot be used on the " "%select{left|right}0 hand side of operator '%1'">; def warn_cxx98_compat_trailing_return_type : Warning< "trailing return types are incompatible with C++98">, InGroup, DefaultIgnore; def ext_auto_type_specifier : ExtWarn< "'auto' type specifier is a C++11 extension">, InGroup; def warn_auto_storage_class : Warning< "'auto' storage class specifier is redundant and incompatible with C++11">, InGroup, DefaultIgnore; def ext_auto_storage_class : ExtWarn< "'auto' storage class specifier is not permitted in C++11, and will not " "be supported in future releases">, InGroup>; def ext_for_range : ExtWarn< "range-based for loop is a C++11 extension">, InGroup; def warn_cxx98_compat_for_range : Warning< "range-based for loop is incompatible with C++98">, InGroup, DefaultIgnore; def err_for_range_expected_decl : Error< "for range declaration must declare a variable">; def err_argument_required_after_attribute : Error< "argument required after attribute">; def err_missing_param : Error<"expected parameter declarator">; def err_missing_comma_before_ellipsis : Error< "C requires a comma prior to the ellipsis in a variadic function type">; def err_unexpected_typedef_ident : Error< "unexpected type name %0: expected identifier">; def warn_cxx98_compat_decltype : Warning< "'decltype' type specifier is incompatible with C++98">, InGroup, DefaultIgnore; def err_unexpected_scope_on_base_decltype : Error< "unexpected namespace scope prior to decltype">; def err_expected_class_name : Error<"expected class name">; def err_expected_class_name_not_template : Error<"'typename' is redundant; base classes are implicitly types">; def err_unspecified_vla_size_with_static : Error< "'static' may not be used with an unspecified variable length array size">; def err_expected_case_before_expression: Error< "expected 'case' keyword before expression">; // Declarations. def err_typename_requires_specqual : Error< "type name requires a specifier or qualifier">; def err_typename_invalid_storageclass : Error< "type name does not allow storage class to be specified">; def err_typename_invalid_functionspec : Error< "type name does not allow function specifier to be specified">; def err_typename_invalid_constexpr : Error< "type name does not allow constexpr specifier to be specified">; def err_typename_identifiers_only : Error< "typename is allowed for identifiers only">; def err_invalid_decl_spec_combination : Error< "cannot combine with previous '%0' declaration specifier">; def err_invalid_vector_decl_spec_combination : Error< "cannot combine with previous '%0' declaration specifier. " "'__vector' must be first">; def err_invalid_pixel_decl_spec_combination : Error< "'__pixel' must be preceded by '__vector'. " "'%0' declaration specifier not allowed here">; def err_invalid_vector_decl_spec : Error< "cannot use '%0' with '__vector'">; def err_invalid_vector_bool_decl_spec : Error< "cannot use '%0' with '__vector bool'">; def warn_vector_long_decl_spec_combination : Warning< "Use of 'long' with '__vector' is deprecated">, InGroup; def err_friend_invalid_in_context : Error< "'friend' used outside of class">; def err_unknown_typename : Error< "unknown type name %0">; def err_use_of_tag_name_without_tag : Error< "must use '%1' tag to refer to type %0%select{| in this scope}2">; def err_templated_using_directive : Error< "cannot template a using directive">; def err_templated_using_declaration : Error< "cannot template a using declaration">; def err_unexected_colon_in_nested_name_spec : Error< "unexpected ':' in nested name specifier">; def err_bool_redeclaration : Error< "redeclaration of C++ built-in type 'bool'">; def ext_c11_static_assert : Extension< "_Static_assert is a C11-specific feature">, InGroup; def warn_cxx98_compat_static_assert : Warning< "static_assert declarations are incompatible with C++98">, InGroup, DefaultIgnore; /// Objective-C parser diagnostics def err_expected_minus_or_plus : Error< "method type specifier must start with '-' or '+'">; def err_objc_no_attributes_on_category : Error< "attributes may not be specified on a category">; def err_objc_missing_end : Error<"missing '@end'">; def note_objc_container_start : Note< "%select{class|protocol|category|class extension|implementation" "|category implementation}0 started here">; def warn_objc_protocol_qualifier_missing_id : Warning< "protocol qualifiers without 'id' is archaic">; def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">; def err_illegal_super_cast : Error< "cannot cast 'super' (it isn't an expression)">; def err_nsnumber_nonliteral_unary : Error< "@%0 must be followed by a number to form an NSNumber object">; let CategoryName = "ARC Parse Issue" in { def err_arc_bridge_retain : Error< "unknown cast annotation __bridge_retain; did you mean __bridge_retained?">; // To be default mapped to an error later. def warn_arc_bridge_cast_nonarc : Warning< "'%0' casts have no effect when not using ARC">, InGroup>; } def err_objc_illegal_visibility_spec : Error< "illegal visibility specification">; def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">; def err_objc_expected_equal_for_getter : Error< "expected '=' for Objective-C getter">; def err_objc_expected_equal_for_setter : Error< "expected '=' for Objective-C setter">; def err_objc_expected_selector_for_getter_setter : Error< "expected selector for Objective-C %select{setter|getter}0">; def err_objc_property_requires_field_name : Error< "property requires fields to be named">; def err_objc_property_bitfield : Error<"property name cannot be a bitfield">; def err_objc_expected_property_attr : Error<"unknown property attribute %0">; def err_objc_properties_require_objc2 : Error< "properties are an Objective-C 2 feature">; def err_objc_unexpected_attr : Error< "prefix attribute must be followed by an interface or protocol">; def err_objc_directive_only_in_protocol : Error< "directive may only be specified in protocols only">; def err_missing_catch_finally : Error< "@try statement without a @catch and @finally clause">; def err_objc_concat_string : Error<"unexpected token after Objective-C string">; def err_expected_objc_container : Error< "'@end' must appear in an Objective-C context">; def error_property_ivar_decl : Error< "property synthesize requires specification of an ivar">; def err_synthesized_property_name : Error< "expected a property name in @synthesize">; def warn_semicolon_before_method_body : Warning< "semicolon before method body is ignored">, InGroup>, DefaultIgnore; def err_expected_field_designator : Error< "expected a field designator, such as '.field = 4'">; def err_declaration_does_not_declare_param : Error< "declaration does not declare a parameter">; def err_no_matching_param : Error<"parameter named %0 is missing">; /// C++ parser diagnostics def err_expected_unqualified_id : Error< "expected %select{identifier|unqualified-id}0">; def err_func_def_no_params : Error< "function definition does not declare parameters">; def err_expected_lparen_after_type : Error< "expected '(' for function-style cast or type construction">; def err_expected_init_in_condition : Error< "variable declaration in condition must have an initializer">; def err_expected_init_in_condition_lparen : Error< "variable declaration in condition cannot have a parenthesized initializer">; def warn_parens_disambiguated_as_function_decl : Warning< "parentheses were disambiguated as a function declarator">, InGroup; def warn_dangling_else : Warning< "add explicit braces to avoid dangling else">, InGroup; def err_expected_member_or_base_name : Error< "expected class member or base class name">; def err_expected_lbrace_after_base_specifiers : Error< "expected '{' after base class list">; def ext_ellipsis_exception_spec : Extension< "exception specification of '...' is a Microsoft extension">; def err_dynamic_and_noexcept_specification : Error< "cannot have both throw() and noexcept() clause on the same function">; -def err_except_spec_unparsed : Error< - "unexpected end of exception specification">; def warn_cxx98_compat_noexcept_decl : Warning< "noexcept specifications are incompatible with C++98">, InGroup, DefaultIgnore; def err_expected_catch : Error<"expected catch">; def err_expected_lbrace_or_comma : Error<"expected '{' or ','">; def err_expected_rbrace_or_comma : Error<"expected '}' or ','">; def err_expected_rsquare_or_comma : Error<"expected ']' or ','">; def err_using_namespace_in_class : Error< "'using namespace' is not allowed in classes">; def err_destructor_tilde_identifier : Error< "expected a class name after '~' to name a destructor">; def err_destructor_template_id : Error< "destructor name %0 does not refer to a template">; def err_default_arg_unparsed : Error< "unexpected end of default argument expression">; def err_parser_impl_limit_overflow : Error< "parser recursion limit reached, program too complex">, DefaultFatal; def err_misplaced_ellipsis_in_declaration : Error< "'...' must %select{immediately precede declared identifier|" "be innermost component of anonymous pack declaration}0">; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; // C++ operator overloading def err_literal_operator_string_prefix : Error< "string literal after 'operator' cannot have an encoding prefix">; def err_literal_operator_string_not_empty : Error< "string literal after 'operator' must be '\"\"'">; def err_literal_operator_missing_space : Error< "C++11 requires a space between the \"\" and the user-defined suffix in a " "literal operator">; def warn_cxx98_compat_literal_operator : Warning< "literal operators are incompatible with C++98">, InGroup, DefaultIgnore; // Classes. def err_anon_type_definition : Error< "declaration of anonymous %0 must be a definition">; def err_default_delete_in_multiple_declaration : Error< "'= %select{default|delete}0' is a function definition and must occur in a " "standalone declaration">; def warn_cxx98_compat_noexcept_expr : Warning< "noexcept expressions are incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_nullptr : Warning< "'nullptr' is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_attribute : Warning< "attributes are incompatible with C++98">, InGroup, DefaultIgnore; def err_cxx11_attribute_forbids_arguments : Error< "attribute '%0' cannot have an argument list">; def err_cxx11_attribute_forbids_ellipsis : Error< "attribute '%0' cannot be used as an attribute pack">; def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; def err_l_square_l_square_not_attribute : Error< "C++11 only allows consecutive left square brackets when " "introducing an attribute">; def err_alignas_pack_exp_unsupported : Error< "pack expansions in alignment specifiers are not supported yet">; /// C++ Templates def err_expected_template : Error<"expected template">; def err_unknown_template_name : Error< "unknown template name %0">; def err_expected_comma_greater : Error< "expected ',' or '>' in template-parameter-list">; def err_class_on_template_template_param : Error< "template template parameter requires 'class' after the parameter list">; def err_template_spec_syntax_non_template : Error< "identifier followed by '<' indicates a class template specialization but " "%0 %select{does not refer to a template|refers to a function " "template||refers to a template template parameter}1">; def err_id_after_template_in_nested_name_spec : Error< "expected template name after 'template' keyword in nested name specifier">; def err_two_right_angle_brackets_need_space : Error< "a space is required between consecutive right angle brackets (use '> >')">; def warn_cxx0x_right_shift_in_template_arg : Warning< "use of right-shift operator ('>>') in template argument will require " "parentheses in C++11">; def warn_cxx98_compat_two_right_angle_brackets : Warning< "consecutive right angle brackets are incompatible with C++98 (use '> >')">, InGroup, DefaultIgnore; def err_multiple_template_declarators : Error< "%select{|a template declaration|an explicit template specialization|" "an explicit template instantiation}0 can " "only %select{|declare|declare|instantiate}0 a single entity">; def err_explicit_instantiation_with_definition : Error< "explicit template instantiation cannot have a definition; if this " "definition is meant to be an explicit specialization, add '<>' after the " "'template' keyword">; def err_enum_template : Error<"enumeration cannot be a template">; def err_explicit_instantiation_enum : Error< "enumerations cannot be explicitly instantiated">; def err_expected_template_parameter : Error<"expected template parameter">; def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; def warn_missing_dependent_template_keyword : ExtWarn< "use 'template' keyword to treat '%0' as a dependent template name">; def ext_extern_template : Extension< "extern templates are a C++11 extension">, InGroup; def warn_cxx98_compat_extern_template : Warning< "extern templates are incompatible with C++98">, InGroup, DefaultIgnore; def warn_static_inline_explicit_inst_ignored : Warning< "ignoring '%select{static|inline}0' keyword on explicit template " "instantiation">; // Constructor template diagnostics. def err_out_of_line_constructor_template_id : Error< "out-of-line constructor for %0 cannot have template arguments">; def err_out_of_line_template_id_names_constructor : Error< "qualified reference to %0 is a constructor name rather than a " "template name wherever a constructor can be declared">; def err_out_of_line_type_names_constructor : Error< "qualified reference to %0 is a constructor name rather than a " "type wherever a constructor can be declared">; def err_expected_qualified_after_typename : Error< "expected a qualified name after 'typename'">; def warn_expected_qualified_after_typename : ExtWarn< "expected a qualified name after 'typename'">; def err_expected_semi_after_tagdecl : Error< "expected ';' after %0">; def err_typename_refers_to_non_type_template : Error< "typename specifier refers to a non-template">; def err_expected_type_name_after_typename : Error< "expected an identifier or template-id after '::'">; def err_explicit_spec_non_template : Error< "explicit %select{specialization|instantiation}0 of non-template " "%select{class|struct|union}1 %2">; def err_default_template_template_parameter_not_template : Error< "default template argument for a template template parameter must be a class " "template">; def err_ctor_init_missing_comma : Error< "missing ',' between base or member initializers">; // C++ declarations def err_friend_decl_defines_type : Error< "cannot define a type in a friend declaration">; def err_missing_whitespace_digraph : Error< "found '<::' after a " "%select{template name|const_cast|dynamic_cast|reinterpret_cast|static_cast}0" " which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">; def ext_deleted_function : ExtWarn< "deleted function definitions are a C++11 extension">, InGroup; def warn_cxx98_compat_deleted_function : Warning< "deleted function definitions are incompatible with C++98">, InGroup, DefaultIgnore; def ext_defaulted_function : ExtWarn< "defaulted function definitions are a C++11 extension">, InGroup; def warn_cxx98_compat_defaulted_function : Warning< "defaulted function definitions are incompatible with C++98">, InGroup, DefaultIgnore; // C++11 in-class member initialization def ext_nonstatic_member_init : ExtWarn< "in-class initialization of non-static data member is a C++11 extension">, InGroup; def warn_cxx98_compat_nonstatic_member_init : Warning< "in-class initialization of non-static data members is incompatible with C++98">, InGroup, DefaultIgnore; def err_bitfield_member_init: Error< "bitfield member cannot have an in-class initializer">; def err_incomplete_array_member_init: Error< "array bound cannot be deduced from an in-class initializer">; // C++11 alias-declaration def ext_alias_declaration : ExtWarn< "alias declarations are a C++11 extension">, InGroup; def warn_cxx98_compat_alias_declaration : Warning< "alias declarations are incompatible with C++98">, InGroup, DefaultIgnore; def err_alias_declaration_not_identifier : Error< "name defined in alias declaration must be an identifier">; def err_alias_declaration_specialization : Error< "%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">; // C++11 override control def ext_override_control_keyword : ExtWarn< "'%0' keyword is a C++11 extension">, InGroup; def warn_cxx98_compat_override_control_keyword : Warning< "'%0' keyword is incompatible with C++98">, InGroup, DefaultIgnore; def err_duplicate_virt_specifier : Error< "class member already marked '%0'">; def err_scoped_enum_missing_identifier : Error< "scoped enumeration requires a name">; def warn_cxx98_compat_scoped_enum : Warning< "scoped enumerations are incompatible with C++98">, InGroup, DefaultIgnore; def err_expected_parameter_pack : Error< "expected the name of a parameter pack">; def err_paren_sizeof_parameter_pack : Error< "missing parentheses around the size of parameter pack %0">; def err_sizeof_parameter_pack : Error< "expected parenthesized parameter pack name in 'sizeof...' expression">; // C++11 lambda expressions def err_expected_comma_or_rsquare : Error< "expected ',' or ']' in lambda capture list">; def err_this_captured_by_reference : Error< "'this' cannot be captured by reference">; def err_expected_capture : Error< "expected variable name or 'this' in lambda capture list">; def err_expected_lambda_body : Error<"expected body of lambda expression">; def warn_cxx98_compat_lambda : Warning< "lambda expressions are incompatible with C++98">, InGroup, DefaultIgnore; def err_lambda_missing_parens : Error< "lambda requires '()' before %select{'mutable'|return type}0">; // Availability attribute def err_expected_version : Error< "expected a version of the form 'major[.minor[.subminor]]'">; def err_zero_version : Error< "version number must have non-zero major, minor, or sub-minor version">; def err_availability_expected_platform : Error< "expected a platform name, e.g., 'macosx'">; def err_availability_expected_change : Error< "expected 'introduced', 'deprecated', or 'obsoleted'">; def err_availability_unknown_change : Error< "%0 is not an availability stage; use 'introduced', 'deprecated', or " "'obsoleted'">; def err_availability_redundant : Error< "redundant %0 availability change; only the last specified change will " "be used">; def warn_availability_and_unavailable : Warning< "'unavailable' availability overrides all other availability information">; // Language specific pragmas // - Generic warnings def warn_pragma_expected_lparen : Warning< "missing '(' after '#pragma %0' - ignoring">; def warn_pragma_expected_rparen : Warning< "missing ')' after '#pragma %0' - ignoring">; def warn_pragma_expected_identifier : Warning< "expected identifier in '#pragma %0' - ignored">; def warn_pragma_ms_struct : Warning< "incorrect use of '#pragma ms_struct on|off' - ignored">; def warn_pragma_extra_tokens_at_eol : Warning< "extra tokens at end of '#pragma %0' - ignored">; // - #pragma options def warn_pragma_options_expected_align : Warning< "expected 'align' following '#pragma options' - ignored">; def warn_pragma_align_expected_equal : Warning< "expected '=' following '#pragma %select{align|options align}0' - ignored">; def warn_pragma_align_invalid_option : Warning< "invalid alignment option in '#pragma %select{align|options align}0' - ignored">; // - #pragma pack def warn_pragma_pack_invalid_action : Warning< "unknown action for '#pragma pack' - ignored">; def warn_pragma_pack_malformed : Warning< "expected integer or identifier in '#pragma pack' - ignored">; // - #pragma unused def warn_pragma_unused_expected_var : Warning< "expected '#pragma unused' argument to be a variable name">; def warn_pragma_unused_expected_punc : Warning< "expected ')' or ',' in '#pragma unused'">; // OpenCL Section 6.8.g def err_not_opencl_storage_class_specifier : Error< "OpenCL does not support the '%0' storage class specifier">; // OpenCL EXTENSION pragma (OpenCL 1.1 [9.1]) def warn_pragma_expected_colon : Warning< "missing ':' after %0 - ignoring">; def warn_pragma_expected_enable_disable : Warning< "expected 'enable' or 'disable' - ignoring">; def warn_pragma_unknown_extension : Warning< "unknown OpenCL extension %0 - ignoring">; def err_seh_expected_handler : Error< "expected '__except' or '__finally' block">; def err_seh___except_block : Error< "%0 only allowed in __except block">; def err_seh___except_filter : Error< "%0 only allowed in __except filter expression">; def err_seh___finally_block : Error< "%0 only allowed in __finally block">; } // end of Parse Issue category. let CategoryName = "Modules Issue" in { def err_module_expected_ident : Error< "expected a module name after module import">; def err_module_expected_semi : Error< "expected a semicolon name after module name">; } } // end of Parser diagnostics Index: vendor/clang/dist/include/clang/Basic/TokenKinds.def =================================================================== --- vendor/clang/dist/include/clang/Basic/TokenKinds.def (revision 235808) +++ vendor/clang/dist/include/clang/Basic/TokenKinds.def (revision 235809) @@ -1,597 +1,596 @@ //===--- TokenKinds.def - C Family Token Kind Database ----------*- 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 TokenKind database. This includes normal tokens like // tok::ampamp (corresponding to the && token) as well as keywords for various // languages. Users of this file must optionally #define the TOK, KEYWORD, // ALIAS, or PPKEYWORD macros to make use of this file. // //===----------------------------------------------------------------------===// #ifndef TOK #define TOK(X) #endif #ifndef PUNCTUATOR #define PUNCTUATOR(X,Y) TOK(X) #endif #ifndef KEYWORD #define KEYWORD(X,Y) TOK(kw_ ## X) #endif #ifndef ALIAS #define ALIAS(X,Y,Z) #endif #ifndef PPKEYWORD #define PPKEYWORD(X) #endif #ifndef CXX_KEYWORD_OPERATOR #define CXX_KEYWORD_OPERATOR(X,Y) #endif #ifndef OBJC1_AT_KEYWORD #define OBJC1_AT_KEYWORD(X) #endif #ifndef OBJC2_AT_KEYWORD #define OBJC2_AT_KEYWORD(X) #endif #ifndef TESTING_KEYWORD #define TESTING_KEYWORD(X, L) KEYWORD(X, L) #endif #ifndef ANNOTATION #define ANNOTATION(X) TOK(annot_ ## X) #endif //===----------------------------------------------------------------------===// // Preprocessor keywords. //===----------------------------------------------------------------------===// // These have meaning after a '#' at the start of a line. These define enums in // the tok::pp_* namespace. Note that IdentifierInfo::getPPKeywordID must be // manually updated if something is added here. PPKEYWORD(not_keyword) // C99 6.10.1 - Conditional Inclusion. PPKEYWORD(if) PPKEYWORD(ifdef) PPKEYWORD(ifndef) PPKEYWORD(elif) PPKEYWORD(else) PPKEYWORD(endif) PPKEYWORD(defined) // C99 6.10.2 - Source File Inclusion. PPKEYWORD(include) PPKEYWORD(__include_macros) // C99 6.10.3 - Macro Replacement. PPKEYWORD(define) PPKEYWORD(undef) // C99 6.10.4 - Line Control. PPKEYWORD(line) // C99 6.10.5 - Error Directive. PPKEYWORD(error) // C99 6.10.6 - Pragma Directive. PPKEYWORD(pragma) // GNU Extensions. PPKEYWORD(import) PPKEYWORD(include_next) PPKEYWORD(warning) PPKEYWORD(ident) PPKEYWORD(sccs) PPKEYWORD(assert) PPKEYWORD(unassert) // Clang extensions PPKEYWORD(__public_macro) PPKEYWORD(__private_macro) //===----------------------------------------------------------------------===// // Language keywords. //===----------------------------------------------------------------------===// // These define members of the tok::* namespace. TOK(unknown) // Not a token. TOK(eof) // End of file. TOK(eod) // End of preprocessing directive (end of line inside a // directive). TOK(code_completion) // Code completion marker TOK(cxx_defaultarg_end) // C++ default argument end marker -TOK(cxx_exceptspec_end) // C++ exception-specification end marker // C99 6.4.9: Comments. TOK(comment) // Comment (only in -E -C[C] mode) // C99 6.4.2: Identifiers. TOK(identifier) // abcde123 TOK(raw_identifier) // Used only in raw lexing mode. // C99 6.4.4.1: Integer Constants // C99 6.4.4.2: Floating Constants TOK(numeric_constant) // 0x123 // C99 6.4.4: Character Constants TOK(char_constant) // 'a' TOK(wide_char_constant) // L'b' // C++0x Character Constants TOK(utf16_char_constant) // u'a' TOK(utf32_char_constant) // U'a' // C99 6.4.5: String Literals. TOK(string_literal) // "foo" TOK(wide_string_literal) // L"foo" TOK(angle_string_literal)// // C++0x String Literals. TOK(utf8_string_literal) // u8"foo" TOK(utf16_string_literal)// u"foo" TOK(utf32_string_literal)// U"foo" // C99 6.4.6: Punctuators. PUNCTUATOR(l_square, "[") PUNCTUATOR(r_square, "]") PUNCTUATOR(l_paren, "(") PUNCTUATOR(r_paren, ")") PUNCTUATOR(l_brace, "{") PUNCTUATOR(r_brace, "}") PUNCTUATOR(period, ".") PUNCTUATOR(ellipsis, "...") PUNCTUATOR(amp, "&") PUNCTUATOR(ampamp, "&&") PUNCTUATOR(ampequal, "&=") PUNCTUATOR(star, "*") PUNCTUATOR(starequal, "*=") PUNCTUATOR(plus, "+") PUNCTUATOR(plusplus, "++") PUNCTUATOR(plusequal, "+=") PUNCTUATOR(minus, "-") PUNCTUATOR(arrow, "->") PUNCTUATOR(minusminus, "--") PUNCTUATOR(minusequal, "-=") PUNCTUATOR(tilde, "~") PUNCTUATOR(exclaim, "!") PUNCTUATOR(exclaimequal, "!=") PUNCTUATOR(slash, "/") PUNCTUATOR(slashequal, "/=") PUNCTUATOR(percent, "%") PUNCTUATOR(percentequal, "%=") PUNCTUATOR(less, "<") PUNCTUATOR(lessless, "<<") PUNCTUATOR(lessequal, "<=") PUNCTUATOR(lesslessequal, "<<=") PUNCTUATOR(greater, ">") PUNCTUATOR(greatergreater, ">>") PUNCTUATOR(greaterequal, ">=") PUNCTUATOR(greatergreaterequal, ">>=") PUNCTUATOR(caret, "^") PUNCTUATOR(caretequal, "^=") PUNCTUATOR(pipe, "|") PUNCTUATOR(pipepipe, "||") PUNCTUATOR(pipeequal, "|=") PUNCTUATOR(question, "?") PUNCTUATOR(colon, ":") PUNCTUATOR(semi, ";") PUNCTUATOR(equal, "=") PUNCTUATOR(equalequal, "==") PUNCTUATOR(comma, ",") PUNCTUATOR(hash, "#") PUNCTUATOR(hashhash, "##") PUNCTUATOR(hashat, "#@") // C++ Support PUNCTUATOR(periodstar, ".*") PUNCTUATOR(arrowstar, "->*") PUNCTUATOR(coloncolon, "::") // Objective C support. PUNCTUATOR(at, "@") // CUDA support. PUNCTUATOR(lesslessless, "<<<") PUNCTUATOR(greatergreatergreater, ">>>") // C99 6.4.1: Keywords. These turn into kw_* tokens. // Flags allowed: // KEYALL - This is a keyword in all variants of C and C++, or it // is a keyword in the implementation namespace that should // always be treated as a keyword // KEYC99 - This is a keyword introduced to C in C99 // KEYC11 - This is a keyword introduced to C in C11 // KEYCXX - This is a C++ keyword, or a C++-specific keyword in the // implementation namespace // KEYNOCXX - This is a keyword in every non-C++ dialect. // KEYCXX0X - This is a C++ keyword introduced to C++ in C++0x // KEYGNU - This is a keyword if GNU extensions are enabled // KEYMS - This is a keyword if Microsoft extensions are enabled // KEYOPENCL - This is a keyword in OpenCL // KEYALTIVEC - This is a keyword in AltiVec // KEYBORLAND - This is a keyword if Borland extensions are enabled // BOOLSUPPORT - This is a keyword if 'bool' is a built-in type // KEYWORD(auto , KEYALL) KEYWORD(break , KEYALL) KEYWORD(case , KEYALL) KEYWORD(char , KEYALL) KEYWORD(const , KEYALL) KEYWORD(continue , KEYALL) KEYWORD(default , KEYALL) KEYWORD(do , KEYALL) KEYWORD(double , KEYALL) KEYWORD(else , KEYALL) KEYWORD(enum , KEYALL) KEYWORD(extern , KEYALL) KEYWORD(float , KEYALL) KEYWORD(for , KEYALL) KEYWORD(goto , KEYALL) KEYWORD(if , KEYALL) KEYWORD(inline , KEYC99|KEYCXX|KEYGNU) KEYWORD(int , KEYALL) KEYWORD(long , KEYALL) KEYWORD(register , KEYALL) KEYWORD(restrict , KEYC99) KEYWORD(return , KEYALL) KEYWORD(short , KEYALL) KEYWORD(signed , KEYALL) KEYWORD(sizeof , KEYALL) KEYWORD(static , KEYALL) KEYWORD(struct , KEYALL) KEYWORD(switch , KEYALL) KEYWORD(typedef , KEYALL) KEYWORD(union , KEYALL) KEYWORD(unsigned , KEYALL) KEYWORD(void , KEYALL) KEYWORD(volatile , KEYALL) KEYWORD(while , KEYALL) KEYWORD(_Alignas , KEYALL) KEYWORD(_Atomic , KEYALL) KEYWORD(_Bool , KEYNOCXX) KEYWORD(_Complex , KEYALL) KEYWORD(_Generic , KEYALL) KEYWORD(_Imaginary , KEYALL) KEYWORD(_Static_assert , KEYALL) KEYWORD(__func__ , KEYALL) KEYWORD(__objc_yes , KEYALL) KEYWORD(__objc_no , KEYALL) // C++ 2.11p1: Keywords. KEYWORD(asm , KEYCXX|KEYGNU) KEYWORD(bool , BOOLSUPPORT|KEYALTIVEC) KEYWORD(catch , KEYCXX) KEYWORD(class , KEYCXX) KEYWORD(const_cast , KEYCXX) KEYWORD(delete , KEYCXX) KEYWORD(dynamic_cast , KEYCXX) KEYWORD(explicit , KEYCXX) KEYWORD(export , KEYCXX) KEYWORD(false , BOOLSUPPORT|KEYALTIVEC) KEYWORD(friend , KEYCXX) KEYWORD(mutable , KEYCXX) KEYWORD(namespace , KEYCXX) KEYWORD(new , KEYCXX) KEYWORD(operator , KEYCXX) KEYWORD(private , KEYCXX|KEYOPENCL) KEYWORD(protected , KEYCXX) KEYWORD(public , KEYCXX) KEYWORD(reinterpret_cast , KEYCXX) KEYWORD(static_cast , KEYCXX) KEYWORD(template , KEYCXX) KEYWORD(this , KEYCXX) KEYWORD(throw , KEYCXX) KEYWORD(true , BOOLSUPPORT|KEYALTIVEC) KEYWORD(try , KEYCXX) KEYWORD(typename , KEYCXX) KEYWORD(typeid , KEYCXX) KEYWORD(using , KEYCXX) KEYWORD(virtual , KEYCXX) KEYWORD(wchar_t , KEYCXX) // C++ 2.5p2: Alternative Representations. CXX_KEYWORD_OPERATOR(and , ampamp) CXX_KEYWORD_OPERATOR(and_eq , ampequal) CXX_KEYWORD_OPERATOR(bitand , amp) CXX_KEYWORD_OPERATOR(bitor , pipe) CXX_KEYWORD_OPERATOR(compl , tilde) CXX_KEYWORD_OPERATOR(not , exclaim) CXX_KEYWORD_OPERATOR(not_eq , exclaimequal) CXX_KEYWORD_OPERATOR(or , pipepipe) CXX_KEYWORD_OPERATOR(or_eq , pipeequal) CXX_KEYWORD_OPERATOR(xor , caret) CXX_KEYWORD_OPERATOR(xor_eq , caretequal) // C++0x keywords KEYWORD(alignas , KEYCXX0X) KEYWORD(alignof , KEYCXX0X) KEYWORD(char16_t , KEYCXX0X) KEYWORD(char32_t , KEYCXX0X) KEYWORD(constexpr , KEYCXX0X) KEYWORD(decltype , KEYCXX0X) KEYWORD(noexcept , KEYCXX0X) KEYWORD(nullptr , KEYCXX0X) KEYWORD(static_assert , KEYCXX0X) KEYWORD(thread_local , KEYCXX0X) // GNU Extensions (in impl-reserved namespace) KEYWORD(_Decimal32 , KEYALL) KEYWORD(_Decimal64 , KEYALL) KEYWORD(_Decimal128 , KEYALL) KEYWORD(__null , KEYCXX) KEYWORD(__alignof , KEYALL) KEYWORD(__attribute , KEYALL) KEYWORD(__builtin_choose_expr , KEYALL) KEYWORD(__builtin_offsetof , KEYALL) KEYWORD(__builtin_types_compatible_p, KEYALL) KEYWORD(__builtin_va_arg , KEYALL) KEYWORD(__extension__ , KEYALL) KEYWORD(__imag , KEYALL) KEYWORD(__int128 , KEYALL) KEYWORD(__label__ , KEYALL) KEYWORD(__real , KEYALL) KEYWORD(__thread , KEYALL) KEYWORD(__FUNCTION__ , KEYALL) KEYWORD(__PRETTY_FUNCTION__ , KEYALL) // GNU Extensions (outside impl-reserved namespace) KEYWORD(typeof , KEYGNU) // GNU and MS Type Traits KEYWORD(__has_nothrow_assign , KEYCXX) KEYWORD(__has_nothrow_copy , KEYCXX) KEYWORD(__has_nothrow_constructor , KEYCXX) KEYWORD(__has_trivial_assign , KEYCXX) KEYWORD(__has_trivial_copy , KEYCXX) KEYWORD(__has_trivial_constructor , KEYCXX) KEYWORD(__has_trivial_destructor , KEYCXX) KEYWORD(__has_virtual_destructor , KEYCXX) KEYWORD(__is_abstract , KEYCXX) KEYWORD(__is_base_of , KEYCXX) KEYWORD(__is_class , KEYCXX) KEYWORD(__is_convertible_to , KEYCXX) KEYWORD(__is_empty , KEYCXX) KEYWORD(__is_enum , KEYCXX) KEYWORD(__is_final , KEYCXX) // Tentative name - there's no implementation of std::is_literal_type yet. KEYWORD(__is_literal , KEYCXX) // Name for GCC 4.6 compatibility - people have already written libraries using // this name unfortunately. KEYWORD(__is_literal_type , KEYCXX) KEYWORD(__is_pod , KEYCXX) KEYWORD(__is_polymorphic , KEYCXX) KEYWORD(__is_trivial , KEYCXX) KEYWORD(__is_union , KEYCXX) // Clang-only C++ Type Traits KEYWORD(__is_trivially_constructible, KEYCXX) KEYWORD(__is_trivially_copyable , KEYCXX) KEYWORD(__is_trivially_assignable , KEYCXX) KEYWORD(__underlying_type , KEYCXX) // Embarcadero Expression Traits KEYWORD(__is_lvalue_expr , KEYCXX) KEYWORD(__is_rvalue_expr , KEYCXX) // Embarcadero Unary Type Traits KEYWORD(__is_arithmetic , KEYCXX) KEYWORD(__is_floating_point , KEYCXX) KEYWORD(__is_integral , KEYCXX) KEYWORD(__is_complete_type , KEYCXX) KEYWORD(__is_void , KEYCXX) KEYWORD(__is_array , KEYCXX) KEYWORD(__is_function , KEYCXX) KEYWORD(__is_reference , KEYCXX) KEYWORD(__is_lvalue_reference , KEYCXX) KEYWORD(__is_rvalue_reference , KEYCXX) KEYWORD(__is_fundamental , KEYCXX) KEYWORD(__is_object , KEYCXX) KEYWORD(__is_scalar , KEYCXX) KEYWORD(__is_compound , KEYCXX) KEYWORD(__is_pointer , KEYCXX) KEYWORD(__is_member_object_pointer , KEYCXX) KEYWORD(__is_member_function_pointer, KEYCXX) KEYWORD(__is_member_pointer , KEYCXX) KEYWORD(__is_const , KEYCXX) KEYWORD(__is_volatile , KEYCXX) KEYWORD(__is_standard_layout , KEYCXX) KEYWORD(__is_signed , KEYCXX) KEYWORD(__is_unsigned , KEYCXX) // Embarcadero Binary Type Traits KEYWORD(__is_same , KEYCXX) KEYWORD(__is_convertible , KEYCXX) KEYWORD(__array_rank , KEYCXX) KEYWORD(__array_extent , KEYCXX) // Apple Extension. KEYWORD(__private_extern__ , KEYALL) KEYWORD(__module_private__ , KEYALL) // Microsoft Extension. KEYWORD(__declspec , KEYALL) KEYWORD(__cdecl , KEYALL) KEYWORD(__stdcall , KEYALL) KEYWORD(__fastcall , KEYALL) KEYWORD(__thiscall , KEYALL) KEYWORD(__forceinline , KEYALL) KEYWORD(__unaligned , KEYMS) // OpenCL-specific keywords KEYWORD(__kernel , KEYOPENCL) ALIAS("kernel", __kernel , KEYOPENCL) KEYWORD(vec_step , KEYOPENCL|KEYALTIVEC) KEYWORD(__private , KEYOPENCL) KEYWORD(__global , KEYOPENCL) KEYWORD(__local , KEYOPENCL) KEYWORD(__constant , KEYOPENCL) ALIAS("global", __global , KEYOPENCL) ALIAS("local", __local , KEYOPENCL) ALIAS("constant", __constant , KEYOPENCL) KEYWORD(__read_only , KEYOPENCL) KEYWORD(__write_only , KEYOPENCL) KEYWORD(__read_write , KEYOPENCL) ALIAS("read_only", __read_only , KEYOPENCL) ALIAS("write_only", __write_only , KEYOPENCL) ALIAS("read_write", __read_write , KEYOPENCL) KEYWORD(__builtin_astype , KEYOPENCL) // Borland Extensions. KEYWORD(__pascal , KEYALL) // Altivec Extension. KEYWORD(__vector , KEYALTIVEC) KEYWORD(__pixel , KEYALTIVEC) // ARM NEON extensions. ALIAS("__fp16", half , KEYALL) // OpenCL Extension. KEYWORD(half , KEYOPENCL) // Objective-C ARC keywords. KEYWORD(__bridge , KEYARC) KEYWORD(__bridge_transfer , KEYARC) KEYWORD(__bridge_retained , KEYARC) KEYWORD(__bridge_retain , KEYARC) // Alternate spelling for various tokens. There are GCC extensions in all // languages, but should not be disabled in strict conformance mode. ALIAS("__alignof__" , __alignof , KEYALL) ALIAS("__asm" , asm , KEYALL) ALIAS("__asm__" , asm , KEYALL) ALIAS("__attribute__", __attribute, KEYALL) ALIAS("__complex" , _Complex , KEYALL) ALIAS("__complex__" , _Complex , KEYALL) ALIAS("__const" , const , KEYALL) ALIAS("__const__" , const , KEYALL) ALIAS("__decltype" , decltype , KEYCXX) ALIAS("__imag__" , __imag , KEYALL) ALIAS("__inline" , inline , KEYALL) ALIAS("__inline__" , inline , KEYALL) ALIAS("__nullptr" , nullptr , KEYCXX) ALIAS("__real__" , __real , KEYALL) ALIAS("__restrict" , restrict , KEYALL) ALIAS("__restrict__" , restrict , KEYALL) ALIAS("__signed" , signed , KEYALL) ALIAS("__signed__" , signed , KEYALL) ALIAS("__typeof" , typeof , KEYALL) ALIAS("__typeof__" , typeof , KEYALL) ALIAS("__volatile" , volatile , KEYALL) ALIAS("__volatile__" , volatile , KEYALL) // Microsoft extensions which should be disabled in strict conformance mode KEYWORD(__ptr64 , KEYMS) KEYWORD(__ptr32 , KEYMS) KEYWORD(__w64 , KEYMS) KEYWORD(__uuidof , KEYMS | KEYBORLAND) KEYWORD(__try , KEYMS | KEYBORLAND) KEYWORD(__finally , KEYMS | KEYBORLAND) KEYWORD(__leave , KEYMS | KEYBORLAND) KEYWORD(__int64 , KEYMS) KEYWORD(__if_exists , KEYMS) KEYWORD(__if_not_exists , KEYMS) ALIAS("__int8" , char , KEYMS) ALIAS("__int16" , short , KEYMS) ALIAS("__int32" , int , KEYMS) ALIAS("_asm" , asm , KEYMS) ALIAS("_cdecl" , __cdecl , KEYMS | KEYBORLAND) ALIAS("_fastcall" , __fastcall , KEYMS | KEYBORLAND) ALIAS("_stdcall" , __stdcall , KEYMS | KEYBORLAND) ALIAS("_thiscall" , __thiscall , KEYMS) ALIAS("_uuidof" , __uuidof , KEYMS | KEYBORLAND) ALIAS("_inline" , inline , KEYMS) ALIAS("_declspec" , __declspec , KEYMS) ALIAS("__interface" , struct , KEYMS) // Borland Extensions which should be disabled in strict conformance mode. ALIAS("_pascal" , __pascal , KEYBORLAND) // Clang Extensions. ALIAS("__char16_t" , char16_t , KEYCXX) ALIAS("__char32_t" , char32_t , KEYCXX) // Clang-specific keywords enabled only in testing. TESTING_KEYWORD(__unknown_anytype , KEYALL) //===----------------------------------------------------------------------===// // Objective-C @-preceded keywords. //===----------------------------------------------------------------------===// // These have meaning after an '@' in Objective-C mode. These define enums in // the tok::objc_* namespace. OBJC1_AT_KEYWORD(not_keyword) OBJC1_AT_KEYWORD(class) OBJC1_AT_KEYWORD(compatibility_alias) OBJC1_AT_KEYWORD(defs) OBJC1_AT_KEYWORD(encode) OBJC1_AT_KEYWORD(end) OBJC1_AT_KEYWORD(implementation) OBJC1_AT_KEYWORD(interface) OBJC1_AT_KEYWORD(private) OBJC1_AT_KEYWORD(protected) OBJC1_AT_KEYWORD(protocol) OBJC1_AT_KEYWORD(public) OBJC1_AT_KEYWORD(selector) OBJC1_AT_KEYWORD(throw) OBJC1_AT_KEYWORD(try) OBJC1_AT_KEYWORD(catch) OBJC1_AT_KEYWORD(finally) OBJC1_AT_KEYWORD(synchronized) OBJC1_AT_KEYWORD(autoreleasepool) OBJC2_AT_KEYWORD(property) OBJC2_AT_KEYWORD(package) OBJC2_AT_KEYWORD(required) OBJC2_AT_KEYWORD(optional) OBJC2_AT_KEYWORD(synthesize) OBJC2_AT_KEYWORD(dynamic) OBJC2_AT_KEYWORD(__experimental_modules_import) // TODO: What to do about context-sensitive keywords like: // bycopy/byref/in/inout/oneway/out? ANNOTATION(cxxscope) // annotation for a C++ scope spec, e.g. "::foo::bar::" ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly // qualified) typename, e.g. "foo::MyClass", or // template-id that names a type ("std::vector") ANNOTATION(template_id) // annotation for a C++ template-id that names a // function template specialization (not a type), // e.g., "std::swap" ANNOTATION(primary_expr) // annotation for a primary expression ANNOTATION(decltype) // annotation for a decltype expression, // e.g., "decltype(foo.bar())" // Annotation for #pragma unused(...) // For each argument inside the parentheses the pragma handler will produce // one 'pragma_unused' annotation token followed by the argument token. ANNOTATION(pragma_unused) // Annotation for #pragma GCC visibility... // The lexer produces these so that they only take effect when the parser // handles them. ANNOTATION(pragma_vis) // Annotation for #pragma pack... // The lexer produces these so that they only take effect when the parser // handles them. ANNOTATION(pragma_pack) #undef ANNOTATION #undef TESTING_KEYWORD #undef OBJC2_AT_KEYWORD #undef OBJC1_AT_KEYWORD #undef CXX_KEYWORD_OPERATOR #undef PPKEYWORD #undef ALIAS #undef KEYWORD #undef PUNCTUATOR #undef TOK Index: vendor/clang/dist/include/clang/Parse/Parser.h =================================================================== --- vendor/clang/dist/include/clang/Parse/Parser.h (revision 235808) +++ vendor/clang/dist/include/clang/Parse/Parser.h (revision 235809) @@ -1,2226 +1,2231 @@ //===--- Parser.h - C Language Parser ---------------------------*- 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 Parser interface. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_PARSE_PARSER_H #define LLVM_CLANG_PARSE_PARSER_H #include "clang/Basic/Specifiers.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Sema/Sema.h" #include "clang/Sema/DeclSpec.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PrettyStackTrace.h" #include namespace clang { class PragmaHandler; class Scope; class DeclGroupRef; class DiagnosticBuilder; class Parser; class PragmaUnusedHandler; class ColonProtectionRAIIObject; class InMessageExpressionRAIIObject; class PoisonSEHIdentifiersRAIIObject; class VersionTuple; /// PrettyStackTraceParserEntry - If a crash happens while the parser is active, /// an entry is printed for it. class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { const Parser &P; public: PrettyStackTraceParserEntry(const Parser &p) : P(p) {} virtual void print(raw_ostream &OS) const; }; /// PrecedenceLevels - These are precedences for the binary/ternary /// operators in the C99 grammar. These have been named to relate /// with the C99 grammar productions. Low precedences numbers bind /// more weakly than high numbers. namespace prec { enum Level { Unknown = 0, // Not binary operator. Comma = 1, // , Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= Conditional = 3, // ? LogicalOr = 4, // || LogicalAnd = 5, // && InclusiveOr = 6, // | ExclusiveOr = 7, // ^ And = 8, // & Equality = 9, // ==, != Relational = 10, // >=, <=, >, < Shift = 11, // <<, >> Additive = 12, // -, + Multiplicative = 13, // *, /, % PointerToMember = 14 // .*, ->* }; } /// Parser - This implements a parser for the C family of languages. After /// parsing units of the grammar, productions are invoked to handle whatever has /// been read. /// class Parser : public CodeCompletionHandler { friend class PragmaUnusedHandler; friend class ColonProtectionRAIIObject; friend class InMessageExpressionRAIIObject; friend class PoisonSEHIdentifiersRAIIObject; friend class ParenBraceBracketBalancer; Preprocessor &PP; /// Tok - The current token we are peeking ahead. All parsing methods assume /// that this is valid. Token Tok; // PrevTokLocation - The location of the token we previously // consumed. This token is used for diagnostics where we expected to // see a token following another token (e.g., the ';' at the end of // a statement). SourceLocation PrevTokLocation; unsigned short ParenCount, BracketCount, BraceCount; /// Actions - These are the callbacks we invoke as we parse various constructs /// in the file. Sema &Actions; DiagnosticsEngine &Diags; /// ScopeCache - Cache scopes to reduce malloc traffic. enum { ScopeCacheSize = 16 }; unsigned NumCachedScopes; Scope *ScopeCache[ScopeCacheSize]; /// Identifiers used for SEH handling in Borland. These are only /// allowed in particular circumstances // __except block IdentifierInfo *Ident__exception_code, *Ident___exception_code, *Ident_GetExceptionCode; // __except filter expression IdentifierInfo *Ident__exception_info, *Ident___exception_info, *Ident_GetExceptionInfo; // __finally IdentifierInfo *Ident__abnormal_termination, *Ident___abnormal_termination, *Ident_AbnormalTermination; /// Contextual keywords for Microsoft extensions. IdentifierInfo *Ident__except; /// Ident_super - IdentifierInfo for "super", to support fast /// comparison. IdentifierInfo *Ident_super; /// Ident_vector and Ident_pixel - cached IdentifierInfo's for /// "vector" and "pixel" fast comparison. Only present if /// AltiVec enabled. IdentifierInfo *Ident_vector; IdentifierInfo *Ident_pixel; /// Objective-C contextual keywords. mutable IdentifierInfo *Ident_instancetype; /// \brief Identifier for "introduced". IdentifierInfo *Ident_introduced; /// \brief Identifier for "deprecated". IdentifierInfo *Ident_deprecated; /// \brief Identifier for "obsoleted". IdentifierInfo *Ident_obsoleted; /// \brief Identifier for "unavailable". IdentifierInfo *Ident_unavailable; /// \brief Identifier for "message". IdentifierInfo *Ident_message; /// C++0x contextual keywords. mutable IdentifierInfo *Ident_final; mutable IdentifierInfo *Ident_override; OwningPtr AlignHandler; OwningPtr GCCVisibilityHandler; OwningPtr OptionsHandler; OwningPtr PackHandler; OwningPtr MSStructHandler; OwningPtr UnusedHandler; OwningPtr WeakHandler; OwningPtr RedefineExtnameHandler; OwningPtr FPContractHandler; OwningPtr OpenCLExtensionHandler; /// Whether the '>' token acts as an operator or not. This will be /// true except when we are parsing an expression within a C++ /// template argument list, where the '>' closes the template /// argument list. bool GreaterThanIsOperator; /// ColonIsSacred - When this is false, we aggressively try to recover from /// code like "foo : bar" as if it were a typo for "foo :: bar". This is not /// safe in case statements and a few other things. This is managed by the /// ColonProtectionRAIIObject RAII object. bool ColonIsSacred; /// \brief When true, we are directly inside an Objective-C messsage /// send expression. /// /// This is managed by the \c InMessageExpressionRAIIObject class, and /// should not be set directly. bool InMessageExpression; /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; /// Factory object for creating AttributeList objects. AttributeFactory AttrFactory; /// \brief Gathers and cleans up TemplateIdAnnotations when parsing of a /// top-level declaration is finished. SmallVector TemplateIds; IdentifierInfo *getSEHExceptKeyword(); bool SkipFunctionBodies; public: Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies); ~Parser(); const LangOptions &getLangOpts() const { return PP.getLangOpts(); } const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); } Preprocessor &getPreprocessor() const { return PP; } Sema &getActions() const { return Actions; } const Token &getCurToken() const { return Tok; } Scope *getCurScope() const { return Actions.getCurScope(); } Decl *getObjCDeclContext() const { return Actions.getObjCDeclContext(); } // Type forwarding. All of these are statically 'void*', but they may all be // different actual classes based on the actions in place. typedef OpaquePtr DeclGroupPtrTy; typedef OpaquePtr TemplateTy; typedef SmallVector TemplateParameterLists; typedef clang::ExprResult ExprResult; typedef clang::StmtResult StmtResult; typedef clang::BaseResult BaseResult; typedef clang::MemInitResult MemInitResult; typedef clang::TypeResult TypeResult; typedef Expr *ExprArg; typedef ASTMultiPtr MultiStmtArg; typedef Sema::FullExprArg FullExprArg; /// Adorns a ExprResult with Actions to make it an ExprResult ExprResult Owned(ExprResult res) { return ExprResult(res); } /// Adorns a StmtResult with Actions to make it an StmtResult StmtResult Owned(StmtResult res) { return StmtResult(res); } ExprResult ExprError() { return ExprResult(true); } StmtResult StmtError() { return StmtResult(true); } ExprResult ExprError(const DiagnosticBuilder &) { return ExprError(); } StmtResult StmtError(const DiagnosticBuilder &) { return StmtError(); } ExprResult ExprEmpty() { return ExprResult(false); } // Parsing methods. /// ParseTranslationUnit - All in one method that initializes parses, and /// shuts down the parser. void ParseTranslationUnit(); /// Initialize - Warm up the parser. /// void Initialize(); /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if /// the EOF was encountered. bool ParseTopLevelDecl(DeclGroupPtrTy &Result); private: //===--------------------------------------------------------------------===// // Low-Level token peeking and consumption methods. // /// isTokenParen - Return true if the cur token is '(' or ')'. bool isTokenParen() const { return Tok.getKind() == tok::l_paren || Tok.getKind() == tok::r_paren; } /// isTokenBracket - Return true if the cur token is '[' or ']'. bool isTokenBracket() const { return Tok.getKind() == tok::l_square || Tok.getKind() == tok::r_square; } /// isTokenBrace - Return true if the cur token is '{' or '}'. bool isTokenBrace() const { return Tok.getKind() == tok::l_brace || Tok.getKind() == tok::r_brace; } /// isTokenStringLiteral - True if this token is a string-literal. /// bool isTokenStringLiteral() const { return Tok.getKind() == tok::string_literal || Tok.getKind() == tok::wide_string_literal || Tok.getKind() == tok::utf8_string_literal || Tok.getKind() == tok::utf16_string_literal || Tok.getKind() == tok::utf32_string_literal; } /// \brief Returns true if the current token is '=' or is a type of '='. /// For typos, give a fixit to '=' bool isTokenEqualOrEqualTypo(); /// ConsumeToken - Consume the current 'peek token' and lex the next one. /// This does not work with all kinds of tokens: strings and specific other /// tokens must be consumed with custom methods below. This returns the /// location of the consumed token. SourceLocation ConsumeToken() { assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() && !isTokenBrace() && "Should consume special tokens with Consume*Token"); if (Tok.is(tok::code_completion)) return handleUnexpectedCodeCompletionToken(); PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// ConsumeAnyToken - Dispatch to the right Consume* method based on the /// current token type. This should only be used in cases where the type of /// the token really isn't known, e.g. in error recovery. SourceLocation ConsumeAnyToken() { if (isTokenParen()) return ConsumeParen(); else if (isTokenBracket()) return ConsumeBracket(); else if (isTokenBrace()) return ConsumeBrace(); else if (isTokenStringLiteral()) return ConsumeStringToken(); else return ConsumeToken(); } /// ConsumeParen - This consume method keeps the paren count up-to-date. /// SourceLocation ConsumeParen() { assert(isTokenParen() && "wrong consume method"); if (Tok.getKind() == tok::l_paren) ++ParenCount; else if (ParenCount) --ParenCount; // Don't let unbalanced )'s drive the count negative. PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// ConsumeBracket - This consume method keeps the bracket count up-to-date. /// SourceLocation ConsumeBracket() { assert(isTokenBracket() && "wrong consume method"); if (Tok.getKind() == tok::l_square) ++BracketCount; else if (BracketCount) --BracketCount; // Don't let unbalanced ]'s drive the count negative. PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// ConsumeBrace - This consume method keeps the brace count up-to-date. /// SourceLocation ConsumeBrace() { assert(isTokenBrace() && "wrong consume method"); if (Tok.getKind() == tok::l_brace) ++BraceCount; else if (BraceCount) --BraceCount; // Don't let unbalanced }'s drive the count negative. PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// ConsumeStringToken - Consume the current 'peek token', lexing a new one /// and returning the token kind. This method is specific to strings, as it /// handles string literal concatenation, as per C99 5.1.1.2, translation /// phase #6. SourceLocation ConsumeStringToken() { assert(isTokenStringLiteral() && "Should only consume string literals with this method"); PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// \brief Consume the current code-completion token. /// /// This routine should be called to consume the code-completion token once /// a code-completion action has already been invoked. SourceLocation ConsumeCodeCompletionToken() { assert(Tok.is(tok::code_completion)); PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } ///\ brief When we are consuming a code-completion token without having /// matched specific position in the grammar, provide code-completion results /// based on context. /// /// \returns the source location of the code-completion token. SourceLocation handleUnexpectedCodeCompletionToken(); /// \brief Abruptly cut off parsing; mainly used when we have reached the /// code-completion point. void cutOffParsing() { PP.setCodeCompletionReached(); // Cut off parsing by acting as if we reached the end-of-file. Tok.setKind(tok::eof); } /// \brief Handle the annotation token produced for #pragma unused(...) void HandlePragmaUnused(); /// \brief Handle the annotation token produced for /// #pragma GCC visibility... void HandlePragmaVisibility(); /// \brief Handle the annotation token produced for /// #pragma pack... void HandlePragmaPack(); /// GetLookAheadToken - This peeks ahead N tokens and returns that token /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) /// returns the token after Tok, etc. /// /// Note that this differs from the Preprocessor's LookAhead method, because /// the Parser always has one token lexed that the preprocessor doesn't. /// const Token &GetLookAheadToken(unsigned N) { if (N == 0 || Tok.is(tok::eof)) return Tok; return PP.LookAhead(N-1); } /// NextToken - This peeks ahead one token and returns it without /// consuming it. const Token &NextToken() { return PP.LookAhead(0); } /// \brief RAII class that helps handle the parsing of an open/close delimiter /// pair, such as braces { ... } or parentheses ( ... ). class BalancedDelimiterTracker { Parser& P; tok::TokenKind Kind, Close; SourceLocation (Parser::*Consumer)(); SourceLocation LOpen, LClose; unsigned short &getDepth() { switch (Kind) { case tok::l_brace: return P.BraceCount; case tok::l_square: return P.BracketCount; case tok::l_paren: return P.ParenCount; default: llvm_unreachable("Wrong token kind"); } } enum { MaxDepth = 256 }; bool diagnoseOverflow(); bool diagnoseMissingClose(); public: BalancedDelimiterTracker(Parser& p, tok::TokenKind k) : P(p), Kind(k) { switch (Kind) { default: llvm_unreachable("Unexpected balanced token"); case tok::l_brace: Close = tok::r_brace; Consumer = &Parser::ConsumeBrace; break; case tok::l_paren: Close = tok::r_paren; Consumer = &Parser::ConsumeParen; break; case tok::l_square: Close = tok::r_square; Consumer = &Parser::ConsumeBracket; break; } } SourceLocation getOpenLocation() const { return LOpen; } SourceLocation getCloseLocation() const { return LClose; } SourceRange getRange() const { return SourceRange(LOpen, LClose); } bool consumeOpen() { if (!P.Tok.is(Kind)) return true; if (getDepth() < MaxDepth) { LOpen = (P.*Consumer)(); return false; } return diagnoseOverflow(); } bool expectAndConsume(unsigned DiagID, const char *Msg = "", tok::TokenKind SkipToTok = tok::unknown); bool consumeClose() { if (P.Tok.is(Close)) { LClose = (P.*Consumer)(); return false; } return diagnoseMissingClose(); } void skipToEnd(); }; /// getTypeAnnotation - Read a parsed type out of an annotation token. static ParsedType getTypeAnnotation(Token &Tok) { return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue()); } static void setTypeAnnotation(Token &Tok, ParsedType T) { Tok.setAnnotationValue(T.getAsOpaquePtr()); } /// \brief Read an already-translated primary expression out of an annotation /// token. static ExprResult getExprAnnotation(Token &Tok) { if (Tok.getAnnotationValue()) return ExprResult((Expr *)Tok.getAnnotationValue()); return ExprResult(true); } /// \brief Set the primary expression corresponding to the given annotation /// token. static void setExprAnnotation(Token &Tok, ExprResult ER) { if (ER.isInvalid()) Tok.setAnnotationValue(0); else Tok.setAnnotationValue(ER.get()); } // If NeedType is true, then TryAnnotateTypeOrScopeToken will try harder to // find a type name by attempting typo correction. bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false, bool NeedType = false); bool TryAnnotateCXXScopeToken(bool EnteringContext = false); /// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens, /// replacing them with the non-context-sensitive keywords. This returns /// true if the token was replaced. bool TryAltiVecToken(DeclSpec &DS, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, bool &isInvalid) { if (!getLangOpts().AltiVec || (Tok.getIdentifierInfo() != Ident_vector && Tok.getIdentifierInfo() != Ident_pixel)) return false; return TryAltiVecTokenOutOfLine(DS, Loc, PrevSpec, DiagID, isInvalid); } /// TryAltiVecVectorToken - Check for context-sensitive AltiVec vector /// identifier token, replacing it with the non-context-sensitive __vector. /// This returns true if the token was replaced. bool TryAltiVecVectorToken() { if (!getLangOpts().AltiVec || Tok.getIdentifierInfo() != Ident_vector) return false; return TryAltiVecVectorTokenOutOfLine(); } bool TryAltiVecVectorTokenOutOfLine(); bool TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, bool &isInvalid); /// \brief Get the TemplateIdAnnotation from the token. TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok); /// TentativeParsingAction - An object that is used as a kind of "tentative /// parsing transaction". It gets instantiated to mark the token position and /// after the token consumption is done, Commit() or Revert() is called to /// either "commit the consumed tokens" or revert to the previously marked /// token position. Example: /// /// TentativeParsingAction TPA(*this); /// ConsumeToken(); /// .... /// TPA.Revert(); /// class TentativeParsingAction { Parser &P; Token PrevTok; + unsigned short PrevParenCount, PrevBracketCount, PrevBraceCount; bool isActive; public: explicit TentativeParsingAction(Parser& p) : P(p) { PrevTok = P.Tok; + PrevParenCount = P.ParenCount; + PrevBracketCount = P.BracketCount; + PrevBraceCount = P.BraceCount; P.PP.EnableBacktrackAtThisPos(); isActive = true; } void Commit() { assert(isActive && "Parsing action was finished!"); P.PP.CommitBacktrackedTokens(); isActive = false; } void Revert() { assert(isActive && "Parsing action was finished!"); P.PP.Backtrack(); P.Tok = PrevTok; + P.ParenCount = PrevParenCount; + P.BracketCount = PrevBracketCount; + P.BraceCount = PrevBraceCount; isActive = false; } ~TentativeParsingAction() { assert(!isActive && "Forgot to call Commit or Revert!"); } }; /// ObjCDeclContextSwitch - An object used to switch context from /// an objective-c decl context to its enclosing decl context and /// back. class ObjCDeclContextSwitch { Parser &P; Decl *DC; public: explicit ObjCDeclContextSwitch(Parser &p) : P(p), DC(p.getObjCDeclContext()) { if (DC) P.Actions.ActOnObjCTemporaryExitContainerContext(cast(DC)); } ~ObjCDeclContextSwitch() { if (DC) P.Actions.ActOnObjCReenterContainerContext(cast(DC)); } }; /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the /// input. If so, it is consumed and false is returned. /// /// If the input is malformed, this emits the specified diagnostic. Next, if /// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is /// returned. bool ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned Diag, const char *DiagMsg = "", tok::TokenKind SkipToTok = tok::unknown); /// \brief The parser expects a semicolon and, if present, will consume it. /// /// If the next token is not a semicolon, this emits the specified diagnostic, /// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior /// to the semicolon, consumes that extra token. bool ExpectAndConsumeSemi(unsigned DiagID); //===--------------------------------------------------------------------===// // Scope manipulation /// ParseScope - Introduces a new scope for parsing. The kind of /// scope is determined by ScopeFlags. Objects of this type should /// be created on the stack to coincide with the position where the /// parser enters the new scope, and this object's constructor will /// create that new scope. Similarly, once the object is destroyed /// the parser will exit the scope. class ParseScope { Parser *Self; ParseScope(const ParseScope&); // do not implement ParseScope& operator=(const ParseScope&); // do not implement public: // ParseScope - Construct a new object to manage a scope in the // parser Self where the new Scope is created with the flags // ScopeFlags, but only when ManageScope is true (the default). If // ManageScope is false, this object does nothing. ParseScope(Parser *Self, unsigned ScopeFlags, bool ManageScope = true) : Self(Self) { if (ManageScope) Self->EnterScope(ScopeFlags); else this->Self = 0; } // Exit - Exit the scope associated with this object now, rather // than waiting until the object is destroyed. void Exit() { if (Self) { Self->ExitScope(); Self = 0; } } ~ParseScope() { Exit(); } }; /// EnterScope - Start a new scope. void EnterScope(unsigned ScopeFlags); /// ExitScope - Pop a scope off the scope stack. void ExitScope(); /// \brief RAII object used to modify the scope flags for the current scope. class ParseScopeFlags { Scope *CurScope; unsigned OldFlags; ParseScopeFlags(const ParseScopeFlags &); // do not implement void operator=(const ParseScopeFlags &); // do not implement public: ParseScopeFlags(Parser *Self, unsigned ScopeFlags, bool ManageFlags = true); ~ParseScopeFlags(); }; //===--------------------------------------------------------------------===// // Diagnostic Emission and Error recovery. public: DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID); private: void SuggestParentheses(SourceLocation Loc, unsigned DK, SourceRange ParenRange); void CheckNestedObjCContexts(SourceLocation AtLoc); /// SkipUntil - Read tokens until we get to the specified token, then consume /// it (unless DontConsume is true). Because we cannot guarantee that the /// token will ever occur, this skips to the next token, or to some likely /// good stopping point. If StopAtSemi is true, skipping will stop at a ';' /// character. /// /// If SkipUntil finds the specified token, it returns true, otherwise it /// returns false. bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true, bool DontConsume = false, bool StopAtCodeCompletion = false) { return SkipUntil(llvm::makeArrayRef(T), StopAtSemi, DontConsume, StopAtCodeCompletion); } bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, bool StopAtSemi = true, bool DontConsume = false, bool StopAtCodeCompletion = false) { tok::TokenKind TokArray[] = {T1, T2}; return SkipUntil(TokArray, StopAtSemi, DontConsume,StopAtCodeCompletion); } bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, tok::TokenKind T3, bool StopAtSemi = true, bool DontConsume = false, bool StopAtCodeCompletion = false) { tok::TokenKind TokArray[] = {T1, T2, T3}; return SkipUntil(TokArray, StopAtSemi, DontConsume,StopAtCodeCompletion); } bool SkipUntil(ArrayRef Toks, bool StopAtSemi = true, bool DontConsume = false, bool StopAtCodeCompletion = false); /// SkipMalformedDecl - Read tokens until we get to some likely good stopping /// point for skipping past a simple-declaration. void SkipMalformedDecl(); //===--------------------------------------------------------------------===// // Lexing and parsing of C++ inline methods. struct ParsingClass; /// [class.mem]p1: "... the class is regarded as complete within /// - function bodies /// - default arguments /// - exception-specifications (TODO: C++0x) /// - and brace-or-equal-initializers for non-static data members /// (including such things in nested classes)." /// LateParsedDeclarations build the tree of those elements so they can /// be parsed after parsing the top-level class. class LateParsedDeclaration { public: virtual ~LateParsedDeclaration(); virtual void ParseLexedMethodDeclarations(); virtual void ParseLexedMemberInitializers(); virtual void ParseLexedMethodDefs(); virtual void ParseLexedAttributes(); }; /// Inner node of the LateParsedDeclaration tree that parses /// all its members recursively. class LateParsedClass : public LateParsedDeclaration { public: LateParsedClass(Parser *P, ParsingClass *C); virtual ~LateParsedClass(); virtual void ParseLexedMethodDeclarations(); virtual void ParseLexedMemberInitializers(); virtual void ParseLexedMethodDefs(); virtual void ParseLexedAttributes(); private: Parser *Self; ParsingClass *Class; }; /// Contains the lexed tokens of an attribute with arguments that /// may reference member variables and so need to be parsed at the /// end of the class declaration after parsing all other member /// member declarations. /// FIXME: Perhaps we should change the name of LateParsedDeclaration to /// LateParsedTokens. struct LateParsedAttribute : public LateParsedDeclaration { Parser *Self; CachedTokens Toks; IdentifierInfo &AttrName; SourceLocation AttrNameLoc; SmallVector Decls; explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name, SourceLocation Loc) : Self(P), AttrName(Name), AttrNameLoc(Loc) {} virtual void ParseLexedAttributes(); void addDecl(Decl *D) { Decls.push_back(D); } }; /// A list of late parsed attributes. Used by ParseGNUAttributes. typedef llvm::SmallVector LateParsedAttrList; /// Contains the lexed tokens of a member function definition /// which needs to be parsed at the end of the class declaration /// after parsing all other member declarations. struct LexedMethod : public LateParsedDeclaration { Parser *Self; Decl *D; CachedTokens Toks; /// \brief Whether this member function had an associated template /// scope. When true, D is a template declaration. /// othewise, it is a member function declaration. bool TemplateScope; explicit LexedMethod(Parser* P, Decl *MD) : Self(P), D(MD), TemplateScope(false) {} virtual void ParseLexedMethodDefs(); }; /// LateParsedDefaultArgument - Keeps track of a parameter that may /// have a default argument that cannot be parsed yet because it /// occurs within a member function declaration inside the class /// (C++ [class.mem]p2). struct LateParsedDefaultArgument { explicit LateParsedDefaultArgument(Decl *P, CachedTokens *Toks = 0) : Param(P), Toks(Toks) { } /// Param - The parameter declaration for this parameter. Decl *Param; /// Toks - The sequence of tokens that comprises the default /// argument expression, not including the '=' or the terminating /// ')' or ','. This will be NULL for parameters that have no /// default argument. CachedTokens *Toks; }; /// LateParsedMethodDeclaration - A method declaration inside a class that /// contains at least one entity whose parsing needs to be delayed /// until the class itself is completely-defined, such as a default /// argument (C++ [class.mem]p2). struct LateParsedMethodDeclaration : public LateParsedDeclaration { explicit LateParsedMethodDeclaration(Parser *P, Decl *M) : Self(P), Method(M), TemplateScope(false), ExceptionSpecTokens(0) { } virtual void ParseLexedMethodDeclarations(); Parser* Self; /// Method - The method declaration. Decl *Method; /// \brief Whether this member function had an associated template /// scope. When true, D is a template declaration. /// othewise, it is a member function declaration. bool TemplateScope; /// DefaultArgs - Contains the parameters of the function and /// their default arguments. At least one of the parameters will /// have a default argument, but all of the parameters of the /// method will be stored so that they can be reintroduced into /// scope at the appropriate times. SmallVector DefaultArgs; /// \brief The set of tokens that make up an exception-specification that /// has not yet been parsed. CachedTokens *ExceptionSpecTokens; }; /// LateParsedMemberInitializer - An initializer for a non-static class data /// member whose parsing must to be delayed until the class is completely /// defined (C++11 [class.mem]p2). struct LateParsedMemberInitializer : public LateParsedDeclaration { LateParsedMemberInitializer(Parser *P, Decl *FD) : Self(P), Field(FD) { } virtual void ParseLexedMemberInitializers(); Parser *Self; /// Field - The field declaration. Decl *Field; /// CachedTokens - The sequence of tokens that comprises the initializer, /// including any leading '='. CachedTokens Toks; }; /// LateParsedDeclarationsContainer - During parsing of a top (non-nested) /// C++ class, its method declarations that contain parts that won't be /// parsed until after the definition is completed (C++ [class.mem]p2), /// the method declarations and possibly attached inline definitions /// will be stored here with the tokens that will be parsed to create those /// entities. typedef SmallVector LateParsedDeclarationsContainer; /// \brief Representation of a class that has been parsed, including /// any member function declarations or definitions that need to be /// parsed after the corresponding top-level class is complete. struct ParsingClass { ParsingClass(Decl *TagOrTemplate, bool TopLevelClass) : TopLevelClass(TopLevelClass), TemplateScope(false), TagOrTemplate(TagOrTemplate) { } /// \brief Whether this is a "top-level" class, meaning that it is /// not nested within another class. bool TopLevelClass : 1; /// \brief Whether this class had an associated template /// scope. When true, TagOrTemplate is a template declaration; /// othewise, it is a tag declaration. bool TemplateScope : 1; /// \brief The class or class template whose definition we are parsing. Decl *TagOrTemplate; /// LateParsedDeclarations - Method declarations, inline definitions and /// nested classes that contain pieces whose parsing will be delayed until /// the top-level class is fully defined. LateParsedDeclarationsContainer LateParsedDeclarations; }; /// \brief The stack of classes that is currently being /// parsed. Nested and local classes will be pushed onto this stack /// when they are parsed, and removed afterward. std::stack ClassStack; ParsingClass &getCurrentClass() { assert(!ClassStack.empty() && "No lexed method stacks!"); return *ClassStack.top(); } /// \brief RAII object used to inform the actions that we're /// currently parsing a declaration. This is active when parsing a /// variable's initializer, but not when parsing the body of a /// class or function definition. class ParsingDeclRAIIObject { Sema &Actions; Sema::ParsingDeclState State; bool Popped; public: ParsingDeclRAIIObject(Parser &P) : Actions(P.Actions) { push(); } ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *Other) : Actions(P.Actions) { if (Other) steal(*Other); else push(); } /// Creates a RAII object which steals the state from a different /// object instead of pushing. ParsingDeclRAIIObject(ParsingDeclRAIIObject &Other) : Actions(Other.Actions) { steal(Other); } ~ParsingDeclRAIIObject() { abort(); } /// Resets the RAII object for a new declaration. void reset() { abort(); push(); } /// Signals that the context was completed without an appropriate /// declaration being parsed. void abort() { pop(0); } void complete(Decl *D) { assert(!Popped && "ParsingDeclaration has already been popped!"); pop(D); } private: void steal(ParsingDeclRAIIObject &Other) { State = Other.State; Popped = Other.Popped; Other.Popped = true; } void push() { State = Actions.PushParsingDeclaration(); Popped = false; } void pop(Decl *D) { if (!Popped) { Actions.PopParsingDeclaration(State, D); Popped = true; } } }; /// A class for parsing a DeclSpec. class ParsingDeclSpec : public DeclSpec { ParsingDeclRAIIObject ParsingRAII; public: ParsingDeclSpec(Parser &P) : DeclSpec(P.AttrFactory), ParsingRAII(P) {} ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) : DeclSpec(P.AttrFactory), ParsingRAII(P, RAII) {} void complete(Decl *D) { ParsingRAII.complete(D); } void abort() { ParsingRAII.abort(); } }; /// A class for parsing a declarator. class ParsingDeclarator : public Declarator { ParsingDeclRAIIObject ParsingRAII; public: ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) : Declarator(DS, C), ParsingRAII(P) { } const ParsingDeclSpec &getDeclSpec() const { return static_cast(Declarator::getDeclSpec()); } ParsingDeclSpec &getMutableDeclSpec() const { return const_cast(getDeclSpec()); } void clear() { Declarator::clear(); ParsingRAII.reset(); } void complete(Decl *D) { ParsingRAII.complete(D); } }; /// \brief RAII object used to class ParsingClassDefinition { Parser &P; bool Popped; Sema::ParsingClassState State; public: ParsingClassDefinition(Parser &P, Decl *TagOrTemplate, bool TopLevelClass) : P(P), Popped(false), State(P.PushParsingClass(TagOrTemplate, TopLevelClass)) { } /// \brief Pop this class of the stack. void Pop() { assert(!Popped && "Nested class has already been popped"); Popped = true; P.PopParsingClass(State); } ~ParsingClassDefinition() { if (!Popped) P.PopParsingClass(State); } }; /// \brief Contains information about any template-specific /// information that has been parsed prior to parsing declaration /// specifiers. struct ParsedTemplateInfo { ParsedTemplateInfo() : Kind(NonTemplate), TemplateParams(0), TemplateLoc() { } ParsedTemplateInfo(TemplateParameterLists *TemplateParams, bool isSpecialization, bool lastParameterListWasEmpty = false) : Kind(isSpecialization? ExplicitSpecialization : Template), TemplateParams(TemplateParams), LastParameterListWasEmpty(lastParameterListWasEmpty) { } explicit ParsedTemplateInfo(SourceLocation ExternLoc, SourceLocation TemplateLoc) : Kind(ExplicitInstantiation), TemplateParams(0), ExternLoc(ExternLoc), TemplateLoc(TemplateLoc), LastParameterListWasEmpty(false){ } /// \brief The kind of template we are parsing. enum { /// \brief We are not parsing a template at all. NonTemplate = 0, /// \brief We are parsing a template declaration. Template, /// \brief We are parsing an explicit specialization. ExplicitSpecialization, /// \brief We are parsing an explicit instantiation. ExplicitInstantiation } Kind; /// \brief The template parameter lists, for template declarations /// and explicit specializations. TemplateParameterLists *TemplateParams; /// \brief The location of the 'extern' keyword, if any, for an explicit /// instantiation SourceLocation ExternLoc; /// \brief The location of the 'template' keyword, for an explicit /// instantiation. SourceLocation TemplateLoc; /// \brief Whether the last template parameter list was empty. bool LastParameterListWasEmpty; SourceRange getSourceRange() const LLVM_READONLY; }; /// \brief Contains a late templated function. /// Will be parsed at the end of the translation unit. struct LateParsedTemplatedFunction { explicit LateParsedTemplatedFunction(Decl *MD) : D(MD) {} CachedTokens Toks; /// \brief The template function declaration to be late parsed. Decl *D; }; void LexTemplateFunctionForLateParsing(CachedTokens &Toks); void ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT); typedef llvm::DenseMap LateParsedTemplateMapT; LateParsedTemplateMapT LateParsedTemplateMap; static void LateTemplateParserCallback(void *P, const FunctionDecl *FD); void LateTemplateParser(const FunctionDecl *FD); Sema::ParsingClassState PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass); void DeallocateParsedClasses(ParsingClass *Class); void PopParsingClass(Sema::ParsingClassState); Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs, ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, const VirtSpecifiers& VS, FunctionDefinitionKind DefinitionKind, ExprResult& Init); void ParseCXXNonStaticMemberInitializer(Decl *VarD); void ParseLexedAttributes(ParsingClass &Class); void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, bool EnterScope, bool OnDefinition); void ParseLexedAttribute(LateParsedAttribute &LA, bool EnterScope, bool OnDefinition); void ParseLexedMethodDeclarations(ParsingClass &Class); void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM); void ParseLexedMethodDefs(ParsingClass &Class); void ParseLexedMethodDef(LexedMethod &LM); void ParseLexedMemberInitializers(ParsingClass &Class); void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI); Decl *ParseLexedObjCMethodDefs(LexedMethod &LM); bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks); bool ConsumeAndStoreUntil(tok::TokenKind T1, CachedTokens &Toks, bool StopAtSemi = true, bool ConsumeFinalToken = true) { return ConsumeAndStoreUntil(T1, T1, Toks, StopAtSemi, ConsumeFinalToken); } bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, CachedTokens &Toks, bool StopAtSemi = true, bool ConsumeFinalToken = true); //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. struct ParsedAttributesWithRange : ParsedAttributes { ParsedAttributesWithRange(AttributeFactory &factory) : ParsedAttributes(factory) {} SourceRange Range; }; DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParsingDeclSpec *DS = 0); bool isDeclarationAfterDeclarator(); bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator); DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, AccessSpecifier AS = AS_none); DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, AccessSpecifier AS = AS_none); Decl *ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), LateParsedAttrList *LateParsedAttrs = 0); void ParseKNRParamDeclarations(Declarator &D); // EndLoc, if non-NULL, is filled with the location of the last token of // the simple-asm. ExprResult ParseSimpleAsm(SourceLocation *EndLoc = 0); ExprResult ParseAsmStringLiteral(); // Objective-C External Declarations DeclGroupPtrTy ParseObjCAtDirectives(); DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc); Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, ParsedAttributes &prefixAttrs); void ParseObjCClassInstanceVariables(Decl *interfaceDecl, tok::ObjCKeywordKind visibility, SourceLocation atLoc); bool ParseObjCProtocolReferences(SmallVectorImpl &P, SmallVectorImpl &PLocs, bool WarnOnDeclarations, SourceLocation &LAngleLoc, SourceLocation &EndProtoLoc); bool ParseObjCProtocolQualifiers(DeclSpec &DS); void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, Decl *CDecl); DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc, ParsedAttributes &prefixAttrs); struct ObjCImplParsingDataRAII { Parser &P; Decl *Dcl; typedef SmallVector LateParsedObjCMethodContainer; LateParsedObjCMethodContainer LateParsedObjCMethods; ObjCImplParsingDataRAII(Parser &parser, Decl *D) : P(parser), Dcl(D) { P.CurParsedObjCImpl = this; Finished = false; } ~ObjCImplParsingDataRAII(); void finish(SourceRange AtEnd); bool isFinished() const { return Finished; } private: bool Finished; }; ObjCImplParsingDataRAII *CurParsedObjCImpl; DeclGroupPtrTy ParseObjCAtImplementationDeclaration(SourceLocation AtLoc); DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd); Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc); Decl *ParseObjCPropertySynthesize(SourceLocation atLoc); Decl *ParseObjCPropertyDynamic(SourceLocation atLoc); IdentifierInfo *ParseObjCSelectorPiece(SourceLocation &MethodLocation); // Definitions for Objective-c context sensitive keywords recognition. enum ObjCTypeQual { objc_in=0, objc_out, objc_inout, objc_oneway, objc_bycopy, objc_byref, objc_NumQuals }; IdentifierInfo *ObjCTypeQuals[objc_NumQuals]; bool isTokIdentifier_in() const; ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, Declarator::TheContext Ctx, ParsedAttributes *ParamAttrs); void ParseObjCMethodRequirement(); Decl *ParseObjCMethodPrototype( tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword, bool MethodDefinition = true); Decl *ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword, bool MethodDefinition=true); void ParseObjCPropertyAttribute(ObjCDeclSpec &DS); Decl *ParseObjCMethodDefinition(); //===--------------------------------------------------------------------===// // C99 6.5: Expressions. /// TypeCastState - State whether an expression is or may be a type cast. enum TypeCastState { NotTypeCast = 0, MaybeTypeCast, IsTypeCast }; ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast); ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast); // Expr that doesn't include commas. ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast); ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc); ExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc); ExprResult ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec); ExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, TypeCastState isTypeCast); ExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand = false, TypeCastState isTypeCast = NotTypeCast); /// Returns true if the next token would start a postfix-expression /// suffix. bool isPostfixExpressionSuffixStart() { tok::TokenKind K = Tok.getKind(); return (K == tok::l_square || K == tok::l_paren || K == tok::period || K == tok::arrow || K == tok::plusplus || K == tok::minusminus); } ExprResult ParsePostfixExpressionSuffix(ExprResult LHS); ExprResult ParseUnaryExprOrTypeTraitExpression(); ExprResult ParseBuiltinPrimaryExpression(); ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, bool &isCastExpr, ParsedType &CastTy, SourceRange &CastRange); typedef SmallVector ExprListTy; typedef SmallVector CommaLocsTy; /// ParseExpressionList - Used for C/C++ (argument-)expression-list. bool ParseExpressionList(SmallVectorImpl &Exprs, SmallVectorImpl &CommaLocs, void (Sema::*Completer)(Scope *S, Expr *Data, llvm::ArrayRef Args) = 0, Expr *Data = 0); /// ParenParseOption - Control what ParseParenExpression will parse. enum ParenParseOption { SimpleExpr, // Only parse '(' expression ')' CompoundStmt, // Also allow '(' compound-statement ')' CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}' CastExpr // Also allow '(' type-name ')' }; ExprResult ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, bool isTypeCast, ParsedType &CastTy, SourceLocation &RParenLoc); ExprResult ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ParsedType &CastTy, BalancedDelimiterTracker &Tracker); ExprResult ParseCompoundLiteralExpression(ParsedType Ty, SourceLocation LParenLoc, SourceLocation RParenLoc); ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false); ExprResult ParseGenericSelectionExpression(); ExprResult ParseObjCBoolLiteral(); //===--------------------------------------------------------------------===// // C++ Expressions ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); void CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectTypePtr, bool EnteringContext, IdentifierInfo &II, CXXScopeSpec &SS); bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext, bool *MayBePseudoDestructor = 0, bool IsTypename = false); //===--------------------------------------------------------------------===// // C++0x 5.1.2: Lambda expressions // [...] () -> type {...} ExprResult ParseLambdaExpression(); ExprResult TryParseLambdaExpression(); llvm::Optional ParseLambdaIntroducer(LambdaIntroducer &Intro); bool TryParseLambdaIntroducer(LambdaIntroducer &Intro); ExprResult ParseLambdaExpressionAfterIntroducer( LambdaIntroducer &Intro); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Casts ExprResult ParseCXXCasts(); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Type Identification ExprResult ParseCXXTypeid(); //===--------------------------------------------------------------------===// // C++ : Microsoft __uuidof Expression ExprResult ParseCXXUuidof(); //===--------------------------------------------------------------------===// // C++ 5.2.4: C++ Pseudo-Destructor Expressions ExprResult ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, ParsedType ObjectType); //===--------------------------------------------------------------------===// // C++ 9.3.2: C++ 'this' pointer ExprResult ParseCXXThis(); //===--------------------------------------------------------------------===// // C++ 15: C++ Throw Expression ExprResult ParseThrowExpression(); ExceptionSpecificationType tryParseExceptionSpecification( - bool Delayed, SourceRange &SpecificationRange, SmallVectorImpl &DynamicExceptions, SmallVectorImpl &DynamicExceptionRanges, - ExprResult &NoexceptExpr, - CachedTokens *&ExceptionSpecTokens); + ExprResult &NoexceptExpr); // EndLoc is filled with the location of the last token of the specification. ExceptionSpecificationType ParseDynamicExceptionSpecification( SourceRange &SpecificationRange, SmallVectorImpl &Exceptions, SmallVectorImpl &Ranges); //===--------------------------------------------------------------------===// // C++0x 8: Function declaration trailing-return-type TypeResult ParseTrailingReturnType(SourceRange &Range); //===--------------------------------------------------------------------===// // C++ 2.13.5: C++ Boolean Literals ExprResult ParseCXXBoolLiteral(); //===--------------------------------------------------------------------===// // C++ 5.2.3: Explicit type conversion (functional notation) ExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS); bool isCXXSimpleTypeSpecifier() const; /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. /// This should only be called when the current token is known to be part of /// simple-type-specifier. void ParseCXXSimpleTypeSpecifier(DeclSpec &DS); bool ParseCXXTypeSpecifierSeq(DeclSpec &DS); //===--------------------------------------------------------------------===// // C++ 5.3.4 and 5.3.5: C++ new and delete bool ParseExpressionListOrTypeId(SmallVectorImpl &Exprs, Declarator &D); void ParseDirectNewDeclarator(Declarator &D); ExprResult ParseCXXNewExpression(bool UseGlobal, SourceLocation Start); ExprResult ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start); //===--------------------------------------------------------------------===// // C++ if/switch/while condition expression. bool ParseCXXCondition(ExprResult &ExprResult, Decl *&DeclResult, SourceLocation Loc, bool ConvertToBoolean); //===--------------------------------------------------------------------===// // C++ types //===--------------------------------------------------------------------===// // C99 6.7.8: Initialization. /// ParseInitializer /// initializer: [C99 6.7.8] /// assignment-expression /// '{' ... ExprResult ParseInitializer() { if (Tok.isNot(tok::l_brace)) return ParseAssignmentExpression(); return ParseBraceInitializer(); } bool MayBeDesignationStart(); ExprResult ParseBraceInitializer(); ExprResult ParseInitializerWithPotentialDesignator(); //===--------------------------------------------------------------------===// // clang Expressions ExprResult ParseBlockLiteralExpression(); // ^{...} //===--------------------------------------------------------------------===// // Objective-C Expressions ExprResult ParseObjCAtExpression(SourceLocation AtLocation); ExprResult ParseObjCStringLiteral(SourceLocation AtLoc); ExprResult ParseObjCCharacterLiteral(SourceLocation AtLoc); ExprResult ParseObjCNumericLiteral(SourceLocation AtLoc); ExprResult ParseObjCBooleanLiteral(SourceLocation AtLoc, bool ArgValue); ExprResult ParseObjCArrayLiteral(SourceLocation AtLoc); ExprResult ParseObjCDictionaryLiteral(SourceLocation AtLoc); ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc); ExprResult ParseObjCSelectorExpression(SourceLocation AtLoc); ExprResult ParseObjCProtocolExpression(SourceLocation AtLoc); bool isSimpleObjCMessageExpression(); ExprResult ParseObjCMessageExpression(); ExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc, SourceLocation SuperLoc, ParsedType ReceiverType, ExprArg ReceiverExpr); ExprResult ParseAssignmentExprWithObjCMessageExprStart( SourceLocation LBracloc, SourceLocation SuperLoc, ParsedType ReceiverType, ExprArg ReceiverExpr); bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr); //===--------------------------------------------------------------------===// // C99 6.8: Statements and Blocks. StmtResult ParseStatement(SourceLocation *TrailingElseLoc = 0) { StmtVector Stmts(Actions); return ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc); } StmtResult ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, SourceLocation *TrailingElseLoc = 0); StmtResult ParseStatementOrDeclarationAfterAttributes( StmtVector &Stmts, bool OnlyStatement, SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs); StmtResult ParseExprStatement(); StmtResult ParseLabeledStatement(ParsedAttributesWithRange &attrs); StmtResult ParseCaseStatement(bool MissingCase = false, ExprResult Expr = ExprResult()); StmtResult ParseDefaultStatement(); StmtResult ParseCompoundStatement(bool isStmtExpr = false); StmtResult ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags); StmtResult ParseCompoundStatementBody(bool isStmtExpr = false); bool ParseParenExprOrCondition(ExprResult &ExprResult, Decl *&DeclResult, SourceLocation Loc, bool ConvertToBoolean); StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc); StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc); StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc); StmtResult ParseDoStatement(); StmtResult ParseForStatement(SourceLocation *TrailingElseLoc); StmtResult ParseGotoStatement(); StmtResult ParseContinueStatement(); StmtResult ParseBreakStatement(); StmtResult ParseReturnStatement(); StmtResult ParseAsmStatement(bool &msAsm); StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc); /// \brief Describes the behavior that should be taken for an __if_exists /// block. enum IfExistsBehavior { /// \brief Parse the block; this code is always used. IEB_Parse, /// \brief Skip the block entirely; this code is never used. IEB_Skip, /// \brief Parse the block as a dependent block, which may be used in /// some template instantiations but not others. IEB_Dependent }; /// \brief Describes the condition of a Microsoft __if_exists or /// __if_not_exists block. struct IfExistsCondition { /// \brief The location of the initial keyword. SourceLocation KeywordLoc; /// \brief Whether this is an __if_exists block (rather than an /// __if_not_exists block). bool IsIfExists; /// \brief Nested-name-specifier preceding the name. CXXScopeSpec SS; /// \brief The name we're looking for. UnqualifiedId Name; /// \brief The behavior of this __if_exists or __if_not_exists block /// should. IfExistsBehavior Behavior; }; bool ParseMicrosoftIfExistsCondition(IfExistsCondition& Result); void ParseMicrosoftIfExistsStatement(StmtVector &Stmts); void ParseMicrosoftIfExistsExternalDeclaration(); void ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, AccessSpecifier& CurAS); bool ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, bool &InitExprsOk); bool ParseAsmOperandsOpt(SmallVectorImpl &Names, SmallVectorImpl &Constraints, SmallVectorImpl &Exprs); //===--------------------------------------------------------------------===// // C++ 6: Statements and Blocks StmtResult ParseCXXTryBlock(); StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc); StmtResult ParseCXXCatchBlock(); //===--------------------------------------------------------------------===// // MS: SEH Statements and Blocks StmtResult ParseSEHTryBlock(); StmtResult ParseSEHTryBlockCommon(SourceLocation Loc); StmtResult ParseSEHExceptBlock(SourceLocation Loc); StmtResult ParseSEHFinallyBlock(SourceLocation Loc); //===--------------------------------------------------------------------===// // Objective-C Statements StmtResult ParseObjCAtStatement(SourceLocation atLoc); StmtResult ParseObjCTryStmt(SourceLocation atLoc); StmtResult ParseObjCThrowStmt(SourceLocation atLoc); StmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc); StmtResult ParseObjCAutoreleasePoolStmt(SourceLocation atLoc); //===--------------------------------------------------------------------===// // C99 6.7: Declarations. /// A context for parsing declaration specifiers. TODO: flesh this /// out, there are other significant restrictions on specifiers than /// would be best implemented in the parser. enum DeclSpecContext { DSC_normal, // normal context DSC_class, // class context, enables 'friend' DSC_type_specifier, // C++ type-specifier-seq DSC_trailing, // C++11 trailing-type-specifier in a trailing return type DSC_top_level // top-level/namespace declaration context }; /// Information on a C++0x for-range-initializer found while parsing a /// declaration which turns out to be a for-range-declaration. struct ForRangeInit { SourceLocation ColonLoc; ExprResult RangeExpr; bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); } }; DeclGroupPtrTy ParseDeclaration(StmtVector &Stmts, unsigned Context, SourceLocation &DeclEnd, ParsedAttributesWithRange &attrs); DeclGroupPtrTy ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context, SourceLocation &DeclEnd, ParsedAttributes &attrs, bool RequireSemi, ForRangeInit *FRI = 0); bool MightBeDeclarator(unsigned Context); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, bool AllowFunctionDefinitions, SourceLocation *DeclEnd = 0, ForRangeInit *FRI = 0); Decl *ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); bool ParseAsmAttributesAfterDeclarator(Declarator &D); Decl *ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope); Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope); /// \brief When in code-completion, skip parsing of the function/method body /// unless the body contains the code-completion point. /// /// \returns true if the function body was skipped. bool trySkippingFunctionBody(); bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC); DeclSpecContext getDeclSpecContextFromDeclaratorContext(unsigned Context); void ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), AccessSpecifier AS = AS_none, DeclSpecContext DSC = DSC_normal, LateParsedAttrList *LateAttrs = 0); void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none, DeclSpecContext DSC = DSC_normal); void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, Declarator::TheContext Context); void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC); void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl); void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType, Decl *TagDecl); struct FieldCallback { virtual Decl *invoke(FieldDeclarator &Field) = 0; virtual ~FieldCallback() {} private: virtual void _anchor(); }; struct ObjCPropertyCallback; void ParseStructDeclaration(DeclSpec &DS, FieldCallback &Callback); bool isDeclarationSpecifier(bool DisambiguatingWithExpression = false); bool isTypeSpecifierQualifier(); bool isTypeQualifier() const; /// isKnownToBeTypeSpecifier - Return true if we know that the specified token /// is definitely a type-specifier. Return false if it isn't part of a type /// specifier or if we're not sure. bool isKnownToBeTypeSpecifier(const Token &Tok) const; /// isDeclarationStatement - Disambiguates between a declaration or an /// expression statement, when parsing function bodies. /// Returns true for declaration, false for expression. bool isDeclarationStatement() { if (getLangOpts().CPlusPlus) return isCXXDeclarationStatement(); return isDeclarationSpecifier(true); } /// isForInitDeclaration - Disambiguates between a declaration or an /// expression in the context of the C 'clause-1' or the C++ // 'for-init-statement' part of a 'for' statement. /// Returns true for declaration, false for expression. bool isForInitDeclaration() { if (getLangOpts().CPlusPlus) return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true); return isDeclarationSpecifier(true); } /// \brief Determine whether we are currently at the start of an Objective-C /// class message that appears to be missing the open bracket '['. bool isStartOfObjCClassMessageMissingOpenBracket(); /// \brief Starting with a scope specifier, identifier, or /// template-id that refers to the current class, determine whether /// this is a constructor declarator. bool isConstructorDeclarator(); /// \brief Specifies the context in which type-id/expression /// disambiguation will occur. enum TentativeCXXTypeIdContext { TypeIdInParens, TypeIdAsTemplateArgument }; /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know /// whether the parens contain an expression or a type-id. /// Returns true for a type-id and false for an expression. bool isTypeIdInParens(bool &isAmbiguous) { if (getLangOpts().CPlusPlus) return isCXXTypeId(TypeIdInParens, isAmbiguous); isAmbiguous = false; return isTypeSpecifierQualifier(); } bool isTypeIdInParens() { bool isAmbiguous; return isTypeIdInParens(isAmbiguous); } /// isCXXDeclarationStatement - C++-specialized function that disambiguates /// between a declaration or an expression statement, when parsing function /// bodies. Returns true for declaration, false for expression. bool isCXXDeclarationStatement(); /// isCXXSimpleDeclaration - C++-specialized function that disambiguates /// between a simple-declaration or an expression-statement. /// If during the disambiguation process a parsing error is encountered, /// the function returns true to let the declaration parsing code handle it. /// Returns false if the statement is disambiguated as expression. bool isCXXSimpleDeclaration(bool AllowForRangeDecl); /// isCXXFunctionDeclarator - Disambiguates between a function declarator or /// a constructor-style initializer, when parsing declaration statements. /// Returns true for function declarator and false for constructor-style /// initializer. If 'warnIfAmbiguous' is true a warning will be emitted to /// indicate that the parens were disambiguated as function declarator. /// If during the disambiguation process a parsing error is encountered, /// the function returns true to let the declaration parsing code handle it. bool isCXXFunctionDeclarator(bool warnIfAmbiguous); /// isCXXConditionDeclaration - Disambiguates between a declaration or an /// expression for a condition of a if/switch/while/for statement. /// If during the disambiguation process a parsing error is encountered, /// the function returns true to let the declaration parsing code handle it. bool isCXXConditionDeclaration(); bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous); bool isCXXTypeId(TentativeCXXTypeIdContext Context) { bool isAmbiguous; return isCXXTypeId(Context, isAmbiguous); } /// TPResult - Used as the result value for functions whose purpose is to /// disambiguate C++ constructs by "tentatively parsing" them. /// This is a class instead of a simple enum because the implicit enum-to-bool /// conversions may cause subtle bugs. class TPResult { enum Result { TPR_true, TPR_false, TPR_ambiguous, TPR_error }; Result Res; TPResult(Result result) : Res(result) {} public: static TPResult True() { return TPR_true; } static TPResult False() { return TPR_false; } static TPResult Ambiguous() { return TPR_ambiguous; } static TPResult Error() { return TPR_error; } bool operator==(const TPResult &RHS) const { return Res == RHS.Res; } bool operator!=(const TPResult &RHS) const { return Res != RHS.Res; } }; /// \brief Based only on the given token kind, determine whether we know that /// we're at the start of an expression or a type-specifier-seq (which may /// be an expression, in C++). /// /// This routine does not attempt to resolve any of the trick cases, e.g., /// those involving lookup of identifiers. /// /// \returns \c TPR_true if this token starts an expression, \c TPR_false if /// this token starts a type-specifier-seq, or \c TPR_ambiguous if it cannot /// tell. TPResult isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind); /// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a /// declaration specifier, TPResult::False() if it is not, /// TPResult::Ambiguous() if it could be either a decl-specifier or a /// function-style cast, and TPResult::Error() if a parsing error was /// encountered. If it could be a braced C++11 function-style cast, returns /// BracedCastResult. /// Doesn't consume tokens. TPResult isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False()); // "Tentative parsing" functions, used for disambiguation. If a parsing error // is encountered they will return TPResult::Error(). // Returning TPResult::True()/False() indicates that the ambiguity was // resolved and tentative parsing may stop. TPResult::Ambiguous() indicates // that more tentative parsing is necessary for disambiguation. // They all consume tokens, so backtracking should be used after calling them. TPResult TryParseDeclarationSpecifier(); TPResult TryParseSimpleDeclaration(bool AllowForRangeDecl); TPResult TryParseTypeofSpecifier(); TPResult TryParseProtocolQualifiers(); TPResult TryParseInitDeclaratorList(); TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); TPResult TryParseParameterDeclarationClause(); TPResult TryParseFunctionDeclarator(); TPResult TryParseBracketDeclarator(); TypeResult ParseTypeName(SourceRange *Range = 0, Declarator::TheContext Context = Declarator::TypeNameContext, AccessSpecifier AS = AS_none, Decl **OwnedType = 0); void ParseBlockId(); // Check for the start of a C++11 attribute-specifier-seq in a context where // an attribute is not allowed. bool CheckProhibitedCXX11Attribute() { assert(Tok.is(tok::l_square)); if (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square)) return false; return DiagnoseProhibitedCXX11Attribute(); } bool DiagnoseProhibitedCXX11Attribute(); void ProhibitAttributes(ParsedAttributesWithRange &attrs) { if (!attrs.Range.isValid()) return; DiagnoseProhibitedAttributes(attrs); attrs.clear(); } void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs); void MaybeParseGNUAttributes(Declarator &D, LateParsedAttrList *LateAttrs = 0) { if (Tok.is(tok::kw___attribute)) { ParsedAttributes attrs(AttrFactory); SourceLocation endLoc; ParseGNUAttributes(attrs, &endLoc, LateAttrs); D.takeAttributes(attrs, endLoc); } } void MaybeParseGNUAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = 0, LateParsedAttrList *LateAttrs = 0) { if (Tok.is(tok::kw___attribute)) ParseGNUAttributes(attrs, endLoc, LateAttrs); } void ParseGNUAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = 0, LateParsedAttrList *LateAttrs = 0); void ParseGNUAttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc); void MaybeParseCXX0XAttributes(Declarator &D) { if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); SourceLocation endLoc; ParseCXX11Attributes(attrs, &endLoc); D.takeAttributes(attrs, endLoc); } } void MaybeParseCXX0XAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = 0) { if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrsWithRange(AttrFactory); ParseCXX11Attributes(attrsWithRange, endLoc); attrs.takeAllFrom(attrsWithRange); } } void MaybeParseCXX0XAttributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc = 0, bool OuterMightBeMessageSend = false) { if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) ParseCXX11Attributes(attrs, endLoc); } void ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SourceLocation *EndLoc = 0); void ParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *EndLoc = 0); IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc); void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = 0) { if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square)) ParseMicrosoftAttributes(attrs, endLoc); } void ParseMicrosoftAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = 0); void ParseMicrosoftDeclSpec(ParsedAttributes &attrs); void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs); void ParseBorlandTypeAttributes(ParsedAttributes &attrs); void ParseOpenCLAttributes(ParsedAttributes &attrs); void ParseOpenCLQualifiers(DeclSpec &DS); VersionTuple ParseVersionTuple(SourceRange &Range); void ParseAvailabilityAttribute(IdentifierInfo &Availability, SourceLocation AvailabilityLoc, ParsedAttributes &attrs, SourceLocation *endLoc); bool IsThreadSafetyAttribute(llvm::StringRef AttrName); void ParseThreadSafetyAttribute(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc); void ParseTypeofSpecifier(DeclSpec &DS); SourceLocation ParseDecltypeSpecifier(DeclSpec &DS); void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, SourceLocation StartLoc, SourceLocation EndLoc); void ParseUnderlyingTypeSpecifier(DeclSpec &DS); void ParseAtomicSpecifier(DeclSpec &DS); ExprResult ParseAlignArgument(SourceLocation Start, SourceLocation &EllipsisLoc); void ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *endLoc = 0); VirtSpecifiers::Specifier isCXX0XVirtSpecifier(const Token &Tok) const; VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const { return isCXX0XVirtSpecifier(Tok); } void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS); bool isCXX0XFinalKeyword() const; /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to /// enter a new C++ declarator scope and exit it when the function is /// finished. class DeclaratorScopeObj { Parser &P; CXXScopeSpec &SS; bool EnteredScope; bool CreatedScope; public: DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) : P(p), SS(ss), EnteredScope(false), CreatedScope(false) {} void EnterDeclaratorScope() { assert(!EnteredScope && "Already entered the scope!"); assert(SS.isSet() && "C++ scope was not set!"); CreatedScope = true; P.EnterScope(0); // Not a decl scope. if (!P.Actions.ActOnCXXEnterDeclaratorScope(P.getCurScope(), SS)) EnteredScope = true; } ~DeclaratorScopeObj() { if (EnteredScope) { assert(SS.isSet() && "C++ scope was cleared ?"); P.Actions.ActOnCXXExitDeclaratorScope(P.getCurScope(), SS); } if (CreatedScope) P.ExitScope(); } }; /// ParseDeclarator - Parse and verify a newly-initialized declarator. void ParseDeclarator(Declarator &D); /// A function that parses a variant of direct-declarator. typedef void (Parser::*DirectDeclParseFunction)(Declarator&); void ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser); void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true, bool CXX0XAttributesAllowed = true); void ParseDirectDeclarator(Declarator &D); void ParseParenDeclarator(Declarator &D); void ParseFunctionDeclarator(Declarator &D, ParsedAttributes &attrs, BalancedDelimiterTracker &Tracker, bool RequiresArg = false); bool isFunctionDeclaratorIdentifierList(); void ParseFunctionDeclaratorIdentifierList( Declarator &D, SmallVector &ParamInfo); void ParseParameterDeclarationClause( Declarator &D, ParsedAttributes &attrs, SmallVector &ParamInfo, SourceLocation &EllipsisLoc); void ParseBracketDeclarator(Declarator &D); //===--------------------------------------------------------------------===// // C++ 7: Declarations [dcl.dcl] /// The kind of attribute specifier we have found. enum CXX11AttributeKind { /// This is not an attribute specifier. CAK_NotAttributeSpecifier, /// This should be treated as an attribute-specifier. CAK_AttributeSpecifier, /// The next tokens are '[[', but this is not an attribute-specifier. This /// is ill-formed by C++11 [dcl.attr.grammar]p6. CAK_InvalidAttributeSpecifier }; CXX11AttributeKind isCXX11AttributeSpecifier(bool Disambiguate = false, bool OuterMightBeMessageSend = false); Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd, SourceLocation InlineLoc = SourceLocation()); void ParseInnerNamespace(std::vector& IdentLoc, std::vector& Ident, std::vector& NamespaceLoc, unsigned int index, SourceLocation& InlineLoc, ParsedAttributes& attrs, BalancedDelimiterTracker &Tracker); Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context); Decl *ParseUsingDirectiveOrDeclaration(unsigned Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd, ParsedAttributesWithRange &attrs, Decl **OwnedType = 0); Decl *ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, ParsedAttributes &attrs); Decl *ParseUsingDeclaration(unsigned Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, SourceLocation &DeclEnd, AccessSpecifier AS = AS_none, Decl **OwnedType = 0); Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd); Decl *ParseNamespaceAlias(SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, SourceLocation &DeclEnd); //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, bool EnteringContext, DeclSpecContext DSC); void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, Decl *TagDecl); ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction, SourceLocation &EqualLoc); void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), ParsingDeclRAIIObject *DiagsFromTParams = 0); void ParseConstructorInitializer(Decl *ConstructorDecl); MemInitResult ParseMemInitializer(Decl *ConstructorDecl); void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, Decl *ThisDecl); //===--------------------------------------------------------------------===// // C++ 10: Derived classes [class.derived] TypeResult ParseBaseTypeSpecifier(SourceLocation &BaseLoc, SourceLocation &EndLocation); void ParseBaseClause(Decl *ClassDecl); BaseResult ParseBaseSpecifier(Decl *ClassDecl); AccessSpecifier getAccessSpecifierIfPresent() const; bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext, ParsedType ObjectType, UnqualifiedId &Id, bool AssumeTemplateId); bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, ParsedType ObjectType, UnqualifiedId &Result); bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, ParsedType ObjectType, SourceLocation& TemplateKWLoc, UnqualifiedId &Result); //===--------------------------------------------------------------------===// // C++ 14: Templates [temp] // C++ 14.1: Template Parameters [temp.param] Decl *ParseDeclarationStartingWithTemplate(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS = AS_none, AttributeList *AccessAttrs = 0); Decl *ParseTemplateDeclarationOrSpecialization(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS, AttributeList *AccessAttrs); Decl *ParseSingleDeclarationAfterTemplate( unsigned Context, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, AccessSpecifier AS=AS_none, AttributeList *AccessAttrs = 0); bool ParseTemplateParameters(unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); bool ParseTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams); bool isStartOfTemplateTypeParameter(); Decl *ParseTemplateParameter(unsigned Depth, unsigned Position); Decl *ParseTypeParameter(unsigned Depth, unsigned Position); Decl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); Decl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); // C++ 14.3: Template arguments [temp.arg] typedef SmallVector TemplateArgList; bool ParseTemplateIdAfterTemplateName(TemplateTy Template, SourceLocation TemplateNameLoc, const CXXScopeSpec &SS, bool ConsumeLastToken, SourceLocation &LAngleLoc, TemplateArgList &TemplateArgs, SourceLocation &RAngleLoc); bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &TemplateName, bool AllowTypeAnnotation = true); void AnnotateTemplateIdTokenAsType(); bool IsTemplateArgumentList(unsigned Skip = 0); bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs); ParsedTemplateArgument ParseTemplateTemplateArgument(); ParsedTemplateArgument ParseTemplateArgument(); Decl *ParseExplicitInstantiation(unsigned Context, SourceLocation ExternLoc, SourceLocation TemplateLoc, SourceLocation &DeclEnd, AccessSpecifier AS = AS_none); //===--------------------------------------------------------------------===// // Modules DeclGroupPtrTy ParseModuleImport(SourceLocation AtLoc); //===--------------------------------------------------------------------===// // GNU G++: Type Traits [Type-Traits.html in the GCC manual] ExprResult ParseUnaryTypeTrait(); ExprResult ParseBinaryTypeTrait(); ExprResult ParseTypeTrait(); //===--------------------------------------------------------------------===// // Embarcadero: Arary and Expression Traits ExprResult ParseArrayTypeTrait(); ExprResult ParseExpressionTrait(); //===--------------------------------------------------------------------===// // Preprocessor code-completion pass-through virtual void CodeCompleteDirective(bool InConditional); virtual void CodeCompleteInConditionalExclusion(); virtual void CodeCompleteMacroName(bool IsDefinition); virtual void CodeCompletePreprocessorExpression(); virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned ArgumentIndex); virtual void CodeCompleteNaturalLanguage(); }; } // end namespace clang #endif Index: vendor/clang/dist/include/clang/Sema/DeclSpec.h =================================================================== --- vendor/clang/dist/include/clang/Sema/DeclSpec.h (revision 235808) +++ vendor/clang/dist/include/clang/Sema/DeclSpec.h (revision 235809) @@ -1,1991 +1,1984 @@ //===--- DeclSpec.h - Parsed declaration specifiers -------------*- 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 classes used to store parsed information about // declaration-specifiers and declarators. // // static const int volatile x, *y, *(*(*z)[10])(const void *x); // ------------------------- - -- --------------------------- // declaration-specifiers \ | / // declarators // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_DECLSPEC_H #define LLVM_CLANG_SEMA_DECLSPEC_H #include "clang/Sema/AttributeList.h" #include "clang/Sema/Ownership.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/Lex/Token.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/Lambda.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" namespace clang { class ASTContext; class TypeLoc; class LangOptions; class DiagnosticsEngine; class IdentifierInfo; class NamespaceAliasDecl; class NamespaceDecl; class NestedNameSpecifier; class NestedNameSpecifierLoc; class ObjCDeclSpec; class Preprocessor; class Sema; class Declarator; struct TemplateIdAnnotation; /// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope /// specifier. These can be in 3 states: /// 1) Not present, identified by isEmpty() /// 2) Present, identified by isNotEmpty() /// 2.a) Valid, idenified by isValid() /// 2.b) Invalid, identified by isInvalid(). /// /// isSet() is deprecated because it mostly corresponded to "valid" but was /// often used as if it meant "present". /// /// The actual scope is described by getScopeRep(). class CXXScopeSpec { SourceRange Range; NestedNameSpecifierLocBuilder Builder; public: const SourceRange &getRange() const { return Range; } void setRange(const SourceRange &R) { Range = R; } void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); } void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } SourceLocation getBeginLoc() const { return Range.getBegin(); } SourceLocation getEndLoc() const { return Range.getEnd(); } /// \brief Retrieve the representation of the nested-name-specifier. NestedNameSpecifier *getScopeRep() const { return Builder.getRepresentation(); } /// \brief Extend the current nested-name-specifier by another /// nested-name-specifier component of the form 'type::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. /// /// \param TemplateKWLoc The location of the 'template' keyword, if present. /// /// \param TL The TypeLoc that describes the type preceding the '::'. /// /// \param ColonColonLoc The location of the trailing '::'. void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, SourceLocation ColonColonLoc); /// \brief Extend the current nested-name-specifier by another /// nested-name-specifier component of the form 'identifier::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. /// /// \param Identifier The identifier. /// /// \param IdentifierLoc The location of the identifier. /// /// \param ColonColonLoc The location of the trailing '::'. void Extend(ASTContext &Context, IdentifierInfo *Identifier, SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); /// \brief Extend the current nested-name-specifier by another /// nested-name-specifier component of the form 'namespace::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. /// /// \param Namespace The namespace. /// /// \param NamespaceLoc The location of the namespace name. /// /// \param ColonColonLoc The location of the trailing '::'. void Extend(ASTContext &Context, NamespaceDecl *Namespace, SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); /// \brief Extend the current nested-name-specifier by another /// nested-name-specifier component of the form 'namespace-alias::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. /// /// \param Alias The namespace alias. /// /// \param AliasLoc The location of the namespace alias /// name. /// /// \param ColonColonLoc The location of the trailing '::'. void Extend(ASTContext &Context, NamespaceAliasDecl *Alias, SourceLocation AliasLoc, SourceLocation ColonColonLoc); /// \brief Turn this (empty) nested-name-specifier into the global /// nested-name-specifier '::'. void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); /// \brief Make a new nested-name-specifier from incomplete source-location /// information. /// /// FIXME: This routine should be used very, very rarely, in cases where we /// need to synthesize a nested-name-specifier. Most code should instead use /// \c Adopt() with a proper \c NestedNameSpecifierLoc. void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange R); /// \brief Adopt an existing nested-name-specifier (with source-range /// information). void Adopt(NestedNameSpecifierLoc Other); /// \brief Retrieve a nested-name-specifier with location information, copied /// into the given AST context. /// /// \param Context The context into which this nested-name-specifier will be /// copied. NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; /// \brief Retrieve the location of the name in the last qualifier /// in this nested name specifier. For example: /// ::foo::bar<0>:: /// ^~~ SourceLocation getLastQualifierNameLoc() const; /// No scope specifier. bool isEmpty() const { return !Range.isValid(); } /// A scope specifier is present, but may be valid or invalid. bool isNotEmpty() const { return !isEmpty(); } /// An error occurred during parsing of the scope specifier. bool isInvalid() const { return isNotEmpty() && getScopeRep() == 0; } /// A scope specifier is present, and it refers to a real scope. bool isValid() const { return isNotEmpty() && getScopeRep() != 0; } /// \brief Indicate that this nested-name-specifier is invalid. void SetInvalid(SourceRange R) { assert(R.isValid() && "Must have a valid source range"); if (Range.getBegin().isInvalid()) Range.setBegin(R.getBegin()); Range.setEnd(R.getEnd()); Builder.Clear(); } /// Deprecated. Some call sites intend isNotEmpty() while others intend /// isValid(). bool isSet() const { return getScopeRep() != 0; } void clear() { Range = SourceRange(); Builder.Clear(); } /// \brief Retrieve the data associated with the source-location information. char *location_data() const { return Builder.getBuffer().first; } /// \brief Retrieve the size of the data associated with source-location /// information. unsigned location_size() const { return Builder.getBuffer().second; } }; /// DeclSpec - This class captures information about "declaration specifiers", /// which encompasses storage-class-specifiers, type-specifiers, /// type-qualifiers, and function-specifiers. class DeclSpec { public: // storage-class-specifier // Note: The order of these enumerators is important for diagnostics. enum SCS { SCS_unspecified = 0, SCS_typedef, SCS_extern, SCS_static, SCS_auto, SCS_register, SCS_private_extern, SCS_mutable }; // Import type specifier width enumeration and constants. typedef TypeSpecifierWidth TSW; static const TSW TSW_unspecified = clang::TSW_unspecified; static const TSW TSW_short = clang::TSW_short; static const TSW TSW_long = clang::TSW_long; static const TSW TSW_longlong = clang::TSW_longlong; enum TSC { TSC_unspecified, TSC_imaginary, TSC_complex }; // Import type specifier sign enumeration and constants. typedef TypeSpecifierSign TSS; static const TSS TSS_unspecified = clang::TSS_unspecified; static const TSS TSS_signed = clang::TSS_signed; static const TSS TSS_unsigned = clang::TSS_unsigned; // Import type specifier type enumeration and constants. typedef TypeSpecifierType TST; static const TST TST_unspecified = clang::TST_unspecified; static const TST TST_void = clang::TST_void; static const TST TST_char = clang::TST_char; static const TST TST_wchar = clang::TST_wchar; static const TST TST_char16 = clang::TST_char16; static const TST TST_char32 = clang::TST_char32; static const TST TST_int = clang::TST_int; static const TST TST_int128 = clang::TST_int128; static const TST TST_half = clang::TST_half; static const TST TST_float = clang::TST_float; static const TST TST_double = clang::TST_double; static const TST TST_bool = clang::TST_bool; static const TST TST_decimal32 = clang::TST_decimal32; static const TST TST_decimal64 = clang::TST_decimal64; static const TST TST_decimal128 = clang::TST_decimal128; static const TST TST_enum = clang::TST_enum; static const TST TST_union = clang::TST_union; static const TST TST_struct = clang::TST_struct; static const TST TST_class = clang::TST_class; static const TST TST_typename = clang::TST_typename; static const TST TST_typeofType = clang::TST_typeofType; static const TST TST_typeofExpr = clang::TST_typeofExpr; static const TST TST_decltype = clang::TST_decltype; static const TST TST_underlyingType = clang::TST_underlyingType; static const TST TST_auto = clang::TST_auto; static const TST TST_unknown_anytype = clang::TST_unknown_anytype; static const TST TST_atomic = clang::TST_atomic; static const TST TST_error = clang::TST_error; // type-qualifiers enum TQ { // NOTE: These flags must be kept in sync with Qualifiers::TQ. TQ_unspecified = 0, TQ_const = 1, TQ_restrict = 2, TQ_volatile = 4 }; /// ParsedSpecifiers - Flags to query which specifiers were applied. This is /// returned by getParsedSpecifiers. enum ParsedSpecifiers { PQ_None = 0, PQ_StorageClassSpecifier = 1, PQ_TypeSpecifier = 2, PQ_TypeQualifier = 4, PQ_FunctionSpecifier = 8 }; private: // storage-class-specifier /*SCS*/unsigned StorageClassSpec : 3; unsigned SCS_thread_specified : 1; unsigned SCS_extern_in_linkage_spec : 1; // type-specifier /*TSW*/unsigned TypeSpecWidth : 2; /*TSC*/unsigned TypeSpecComplex : 2; /*TSS*/unsigned TypeSpecSign : 2; /*TST*/unsigned TypeSpecType : 5; unsigned TypeAltiVecVector : 1; unsigned TypeAltiVecPixel : 1; unsigned TypeAltiVecBool : 1; unsigned TypeSpecOwned : 1; // type-qualifiers unsigned TypeQualifiers : 3; // Bitwise OR of TQ. // function-specifier unsigned FS_inline_specified : 1; unsigned FS_virtual_specified : 1; unsigned FS_explicit_specified : 1; // friend-specifier unsigned Friend_specified : 1; // constexpr-specifier unsigned Constexpr_specified : 1; /*SCS*/unsigned StorageClassSpecAsWritten : 3; union { UnionParsedType TypeRep; Decl *DeclRep; Expr *ExprRep; }; // attributes. ParsedAttributes Attrs; // Scope specifier for the type spec, if applicable. CXXScopeSpec TypeScope; // List of protocol qualifiers for objective-c classes. Used for // protocol-qualified interfaces "NString" and protocol-qualified id // "id". Decl * const *ProtocolQualifiers; unsigned NumProtocolQualifiers; SourceLocation ProtocolLAngleLoc; SourceLocation *ProtocolLocs; // SourceLocation info. These are null if the item wasn't specified or if // the setting was synthesized. SourceRange Range; SourceLocation StorageClassSpecLoc, SCS_threadLoc; SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc, AltiVecLoc; /// TSTNameLoc - If TypeSpecType is any of class, enum, struct, union, /// typename, then this is the location of the named type (if present); /// otherwise, it is the same as TSTLoc. Hence, the pair TSTLoc and /// TSTNameLoc provides source range info for tag types. SourceLocation TSTNameLoc; SourceRange TypeofParensRange; SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc; SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; WrittenBuiltinSpecs writtenBS; void SaveWrittenBuiltinSpecs(); void SaveStorageSpecifierAsWritten(); ObjCDeclSpec *ObjCQualifiers; static bool isTypeRep(TST T) { return (T == TST_typename || T == TST_typeofType || T == TST_underlyingType || T == TST_atomic); } static bool isExprRep(TST T) { return (T == TST_typeofExpr || T == TST_decltype); } static bool isDeclRep(TST T) { return (T == TST_enum || T == TST_struct || T == TST_union || T == TST_class); } DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT void operator=(const DeclSpec&); // DO NOT IMPLEMENT public: DeclSpec(AttributeFactory &attrFactory) : StorageClassSpec(SCS_unspecified), SCS_thread_specified(false), SCS_extern_in_linkage_spec(false), TypeSpecWidth(TSW_unspecified), TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified), TypeSpecType(TST_unspecified), TypeAltiVecVector(false), TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), TypeQualifiers(TQ_unspecified), FS_inline_specified(false), FS_virtual_specified(false), FS_explicit_specified(false), Friend_specified(false), Constexpr_specified(false), StorageClassSpecAsWritten(SCS_unspecified), Attrs(attrFactory), ProtocolQualifiers(0), NumProtocolQualifiers(0), ProtocolLocs(0), writtenBS(), ObjCQualifiers(0) { } ~DeclSpec() { delete [] ProtocolQualifiers; delete [] ProtocolLocs; } // storage-class-specifier SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } bool isThreadSpecified() const { return SCS_thread_specified; } bool isExternInLinkageSpec() const { return SCS_extern_in_linkage_spec; } void setExternInLinkageSpec(bool Value) { SCS_extern_in_linkage_spec = Value; } SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; } SourceLocation getThreadSpecLoc() const { return SCS_threadLoc; } void ClearStorageClassSpecs() { StorageClassSpec = DeclSpec::SCS_unspecified; SCS_thread_specified = false; SCS_extern_in_linkage_spec = false; StorageClassSpecLoc = SourceLocation(); SCS_threadLoc = SourceLocation(); } // type-specifier TSW getTypeSpecWidth() const { return (TSW)TypeSpecWidth; } TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; } TSS getTypeSpecSign() const { return (TSS)TypeSpecSign; } TST getTypeSpecType() const { return (TST)TypeSpecType; } bool isTypeAltiVecVector() const { return TypeAltiVecVector; } bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; } bool isTypeAltiVecBool() const { return TypeAltiVecBool; } bool isTypeSpecOwned() const { return TypeSpecOwned; } ParsedType getRepAsType() const { assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type"); return TypeRep; } Decl *getRepAsDecl() const { assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl"); return DeclRep; } Expr *getRepAsExpr() const { assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr"); return ExprRep; } CXXScopeSpec &getTypeSpecScope() { return TypeScope; } const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; } const SourceRange &getSourceRange() const LLVM_READONLY { return Range; } SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } SourceLocation getTypeSpecWidthLoc() const { return TSWLoc; } SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; } SourceLocation getTypeSpecSignLoc() const { return TSSLoc; } SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; } SourceLocation getAltiVecLoc() const { return AltiVecLoc; } SourceLocation getTypeSpecTypeNameLoc() const { assert(isDeclRep((TST) TypeSpecType) || TypeSpecType == TST_typename); return TSTNameLoc; } SourceRange getTypeofParensRange() const { return TypeofParensRange; } void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; } /// getSpecifierName - Turn a type-specifier-type into a string like "_Bool" /// or "union". static const char *getSpecifierName(DeclSpec::TST T); static const char *getSpecifierName(DeclSpec::TQ Q); static const char *getSpecifierName(DeclSpec::TSS S); static const char *getSpecifierName(DeclSpec::TSC C); static const char *getSpecifierName(DeclSpec::TSW W); static const char *getSpecifierName(DeclSpec::SCS S); // type-qualifiers /// getTypeQualifiers - Return a set of TQs. unsigned getTypeQualifiers() const { return TypeQualifiers; } SourceLocation getConstSpecLoc() const { return TQ_constLoc; } SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } /// \brief Clear out all of the type qualifiers. void ClearTypeQualifiers() { TypeQualifiers = 0; TQ_constLoc = SourceLocation(); TQ_restrictLoc = SourceLocation(); TQ_volatileLoc = SourceLocation(); } // function-specifier bool isInlineSpecified() const { return FS_inline_specified; } SourceLocation getInlineSpecLoc() const { return FS_inlineLoc; } bool isVirtualSpecified() const { return FS_virtual_specified; } SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; } bool isExplicitSpecified() const { return FS_explicit_specified; } SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; } void ClearFunctionSpecs() { FS_inline_specified = false; FS_inlineLoc = SourceLocation(); FS_virtual_specified = false; FS_virtualLoc = SourceLocation(); FS_explicit_specified = false; FS_explicitLoc = SourceLocation(); } /// hasTypeSpecifier - Return true if any type-specifier has been found. bool hasTypeSpecifier() const { return getTypeSpecType() != DeclSpec::TST_unspecified || getTypeSpecWidth() != DeclSpec::TSW_unspecified || getTypeSpecComplex() != DeclSpec::TSC_unspecified || getTypeSpecSign() != DeclSpec::TSS_unspecified; } /// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this /// DeclSpec includes. /// unsigned getParsedSpecifiers() const; SCS getStorageClassSpecAsWritten() const { return (SCS)StorageClassSpecAsWritten; } /// isEmpty - Return true if this declaration specifier is completely empty: /// no tokens were parsed in the production of it. bool isEmpty() const { return getParsedSpecifiers() == DeclSpec::PQ_None; } void SetRangeStart(SourceLocation Loc) { Range.setBegin(Loc); } void SetRangeEnd(SourceLocation Loc) { Range.setEnd(Loc); } /// These methods set the specified attribute of the DeclSpec and /// return false if there was no error. If an error occurs (for /// example, if we tried to set "auto" on a spec with "extern" /// already set), they return true and set PrevSpec and DiagID /// such that /// Diag(Loc, DiagID) << PrevSpec; /// will yield a useful result. /// /// TODO: use a more general approach that still allows these /// diagnostics to be ignored when desired. bool SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, ParsedType Rep); bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, Decl *Rep, bool Owned); bool SetTypeSpecType(TST T, SourceLocation TagKwLoc, SourceLocation TagNameLoc, const char *&PrevSpec, unsigned &DiagID, ParsedType Rep); bool SetTypeSpecType(TST T, SourceLocation TagKwLoc, SourceLocation TagNameLoc, const char *&PrevSpec, unsigned &DiagID, Decl *Rep, bool Owned); bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, Expr *Rep); bool SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetTypeSpecError(); void UpdateDeclRep(Decl *Rep) { assert(isDeclRep((TST) TypeSpecType)); DeclRep = Rep; } void UpdateTypeRep(ParsedType Rep) { assert(isTypeRep((TST) TypeSpecType)); TypeRep = Rep; } void UpdateExprRep(Expr *Rep) { assert(isExprRep((TST) TypeSpecType)); ExprRep = Rep; } bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const LangOptions &Lang); bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool isFriendSpecified() const { return Friend_specified; } SourceLocation getFriendSpecLoc() const { return FriendLoc; } bool isModulePrivateSpecified() const { return ModulePrivateLoc.isValid(); } SourceLocation getModulePrivateSpecLoc() const { return ModulePrivateLoc; } bool isConstexprSpecified() const { return Constexpr_specified; } SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; } void ClearConstexprSpec() { Constexpr_specified = false; ConstexprLoc = SourceLocation(); } AttributePool &getAttributePool() const { return Attrs.getPool(); } /// AddAttributes - contatenates two attribute lists. /// The GCC attribute syntax allows for the following: /// /// short __attribute__(( unused, deprecated )) /// int __attribute__(( may_alias, aligned(16) )) var; /// /// This declares 4 attributes using 2 lists. The following syntax is /// also allowed and equivalent to the previous declaration. /// /// short __attribute__((unused)) __attribute__((deprecated)) /// int __attribute__((may_alias)) __attribute__((aligned(16))) var; /// void addAttributes(AttributeList *AL) { Attrs.addAll(AL); } void setAttributes(AttributeList *AL) { Attrs.set(AL); } bool hasAttributes() const { return !Attrs.empty(); } ParsedAttributes &getAttributes() { return Attrs; } const ParsedAttributes &getAttributes() const { return Attrs; } /// TakeAttributes - Return the current attribute list and remove them from /// the DeclSpec so that it doesn't own them. ParsedAttributes takeAttributes() { // The non-const "copy" constructor clears the operand automatically. return Attrs; } void takeAttributesFrom(ParsedAttributes &attrs) { Attrs.takeAllFrom(attrs); } typedef Decl * const *ProtocolQualifierListTy; ProtocolQualifierListTy getProtocolQualifiers() const { return ProtocolQualifiers; } SourceLocation *getProtocolLocs() const { return ProtocolLocs; } unsigned getNumProtocolQualifiers() const { return NumProtocolQualifiers; } SourceLocation getProtocolLAngleLoc() const { return ProtocolLAngleLoc; } void setProtocolQualifiers(Decl * const *Protos, unsigned NP, SourceLocation *ProtoLocs, SourceLocation LAngleLoc); /// Finish - This does final analysis of the declspec, issuing diagnostics for /// things like "_Imaginary" (lacking an FP type). After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void Finish(DiagnosticsEngine &D, Preprocessor &PP); const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const { return writtenBS; } ObjCDeclSpec *getObjCQualifiers() const { return ObjCQualifiers; } void setObjCQualifiers(ObjCDeclSpec *quals) { ObjCQualifiers = quals; } /// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone, /// without a Declarator. Only tag declspecs can stand alone. bool isMissingDeclaratorOk(); }; /// ObjCDeclSpec - This class captures information about /// "declaration specifiers" specific to objective-c class ObjCDeclSpec { public: /// ObjCDeclQualifier - Qualifier used on types in method /// declarations. Not all combinations are sensible. Parameters /// can be one of { in, out, inout } with one of { bycopy, byref }. /// Returns can either be { oneway } or not. /// /// This should be kept in sync with Decl::ObjCDeclQualifier. enum ObjCDeclQualifier { DQ_None = 0x0, DQ_In = 0x1, DQ_Inout = 0x2, DQ_Out = 0x4, DQ_Bycopy = 0x8, DQ_Byref = 0x10, DQ_Oneway = 0x20 }; /// PropertyAttributeKind - list of property attributes. enum ObjCPropertyAttributeKind { DQ_PR_noattr = 0x0, DQ_PR_readonly = 0x01, DQ_PR_getter = 0x02, DQ_PR_assign = 0x04, DQ_PR_readwrite = 0x08, DQ_PR_retain = 0x10, DQ_PR_copy = 0x20, DQ_PR_nonatomic = 0x40, DQ_PR_setter = 0x80, DQ_PR_atomic = 0x100, DQ_PR_weak = 0x200, DQ_PR_strong = 0x400, DQ_PR_unsafe_unretained = 0x800 }; ObjCDeclSpec() : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr), GetterName(0), SetterName(0) { } ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; } void setObjCDeclQualifier(ObjCDeclQualifier DQVal) { objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); } ObjCPropertyAttributeKind getPropertyAttributes() const { return ObjCPropertyAttributeKind(PropertyAttributes); } void setPropertyAttributes(ObjCPropertyAttributeKind PRVal) { PropertyAttributes = (ObjCPropertyAttributeKind)(PropertyAttributes | PRVal); } const IdentifierInfo *getGetterName() const { return GetterName; } IdentifierInfo *getGetterName() { return GetterName; } void setGetterName(IdentifierInfo *name) { GetterName = name; } const IdentifierInfo *getSetterName() const { return SetterName; } IdentifierInfo *getSetterName() { return SetterName; } void setSetterName(IdentifierInfo *name) { SetterName = name; } private: // FIXME: These two are unrelated and mutially exclusive. So perhaps // we can put them in a union to reflect their mutual exclusiveness // (space saving is negligible). ObjCDeclQualifier objcDeclQualifier : 6; // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind unsigned PropertyAttributes : 12; IdentifierInfo *GetterName; // getter name of NULL if no getter IdentifierInfo *SetterName; // setter name of NULL if no setter }; /// \brief Represents a C++ unqualified-id that has been parsed. class UnqualifiedId { private: const UnqualifiedId &operator=(const UnqualifiedId &); // DO NOT IMPLEMENT public: /// \brief Describes the kind of unqualified-id parsed. enum IdKind { /// \brief An identifier. IK_Identifier, /// \brief An overloaded operator name, e.g., operator+. IK_OperatorFunctionId, /// \brief A conversion function name, e.g., operator int. IK_ConversionFunctionId, /// \brief A user-defined literal name, e.g., operator "" _i. IK_LiteralOperatorId, /// \brief A constructor name. IK_ConstructorName, /// \brief A constructor named via a template-id. IK_ConstructorTemplateId, /// \brief A destructor name. IK_DestructorName, /// \brief A template-id, e.g., f. IK_TemplateId, /// \brief An implicit 'self' parameter IK_ImplicitSelfParam } Kind; /// \brief Anonymous union that holds extra data associated with the /// parsed unqualified-id. union { /// \brief When Kind == IK_Identifier, the parsed identifier, or when Kind /// == IK_UserLiteralId, the identifier suffix. IdentifierInfo *Identifier; /// \brief When Kind == IK_OperatorFunctionId, the overloaded operator /// that we parsed. struct { /// \brief The kind of overloaded operator. OverloadedOperatorKind Operator; /// \brief The source locations of the individual tokens that name /// the operator, e.g., the "new", "[", and "]" tokens in /// operator new []. /// /// Different operators have different numbers of tokens in their name, /// up to three. Any remaining source locations in this array will be /// set to an invalid value for operators with fewer than three tokens. unsigned SymbolLocations[3]; } OperatorFunctionId; /// \brief When Kind == IK_ConversionFunctionId, the type that the /// conversion function names. UnionParsedType ConversionFunctionId; /// \brief When Kind == IK_ConstructorName, the class-name of the type /// whose constructor is being referenced. UnionParsedType ConstructorName; /// \brief When Kind == IK_DestructorName, the type referred to by the /// class-name. UnionParsedType DestructorName; /// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId, /// the template-id annotation that contains the template name and /// template arguments. TemplateIdAnnotation *TemplateId; }; /// \brief The location of the first token that describes this unqualified-id, /// which will be the location of the identifier, "operator" keyword, /// tilde (for a destructor), or the template name of a template-id. SourceLocation StartLocation; /// \brief The location of the last token that describes this unqualified-id. SourceLocation EndLocation; UnqualifiedId() : Kind(IK_Identifier), Identifier(0) { } /// \brief Do not use this copy constructor. It is temporary, and only /// exists because we are holding FieldDeclarators in a SmallVector when we /// don't actually need them. /// /// FIXME: Kill this copy constructor. UnqualifiedId(const UnqualifiedId &Other) : Kind(IK_Identifier), Identifier(Other.Identifier), StartLocation(Other.StartLocation), EndLocation(Other.EndLocation) { assert(Other.Kind == IK_Identifier && "Cannot copy non-identifiers"); } /// \brief Destroy this unqualified-id. ~UnqualifiedId() { clear(); } /// \brief Clear out this unqualified-id, setting it to default (invalid) /// state. void clear(); /// \brief Determine whether this unqualified-id refers to a valid name. bool isValid() const { return StartLocation.isValid(); } /// \brief Determine whether this unqualified-id refers to an invalid name. bool isInvalid() const { return !isValid(); } /// \brief Determine what kind of name we have. IdKind getKind() const { return Kind; } void setKind(IdKind kind) { Kind = kind; } /// \brief Specify that this unqualified-id was parsed as an identifier. /// /// \param Id the parsed identifier. /// \param IdLoc the location of the parsed identifier. void setIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc) { Kind = IK_Identifier; Identifier = const_cast(Id); StartLocation = EndLocation = IdLoc; } /// \brief Specify that this unqualified-id was parsed as an /// operator-function-id. /// /// \param OperatorLoc the location of the 'operator' keyword. /// /// \param Op the overloaded operator. /// /// \param SymbolLocations the locations of the individual operator symbols /// in the operator. void setOperatorFunctionId(SourceLocation OperatorLoc, OverloadedOperatorKind Op, SourceLocation SymbolLocations[3]); /// \brief Specify that this unqualified-id was parsed as a /// conversion-function-id. /// /// \param OperatorLoc the location of the 'operator' keyword. /// /// \param Ty the type to which this conversion function is converting. /// /// \param EndLoc the location of the last token that makes up the type name. void setConversionFunctionId(SourceLocation OperatorLoc, ParsedType Ty, SourceLocation EndLoc) { Kind = IK_ConversionFunctionId; StartLocation = OperatorLoc; EndLocation = EndLoc; ConversionFunctionId = Ty; } /// \brief Specific that this unqualified-id was parsed as a /// literal-operator-id. /// /// \param Id the parsed identifier. /// /// \param OpLoc the location of the 'operator' keyword. /// /// \param IdLoc the location of the identifier. void setLiteralOperatorId(const IdentifierInfo *Id, SourceLocation OpLoc, SourceLocation IdLoc) { Kind = IK_LiteralOperatorId; Identifier = const_cast(Id); StartLocation = OpLoc; EndLocation = IdLoc; } /// \brief Specify that this unqualified-id was parsed as a constructor name. /// /// \param ClassType the class type referred to by the constructor name. /// /// \param ClassNameLoc the location of the class name. /// /// \param EndLoc the location of the last token that makes up the type name. void setConstructorName(ParsedType ClassType, SourceLocation ClassNameLoc, SourceLocation EndLoc) { Kind = IK_ConstructorName; StartLocation = ClassNameLoc; EndLocation = EndLoc; ConstructorName = ClassType; } /// \brief Specify that this unqualified-id was parsed as a /// template-id that names a constructor. /// /// \param TemplateId the template-id annotation that describes the parsed /// template-id. This UnqualifiedId instance will take ownership of the /// \p TemplateId and will free it on destruction. void setConstructorTemplateId(TemplateIdAnnotation *TemplateId); /// \brief Specify that this unqualified-id was parsed as a destructor name. /// /// \param TildeLoc the location of the '~' that introduces the destructor /// name. /// /// \param ClassType the name of the class referred to by the destructor name. void setDestructorName(SourceLocation TildeLoc, ParsedType ClassType, SourceLocation EndLoc) { Kind = IK_DestructorName; StartLocation = TildeLoc; EndLocation = EndLoc; DestructorName = ClassType; } /// \brief Specify that this unqualified-id was parsed as a template-id. /// /// \param TemplateId the template-id annotation that describes the parsed /// template-id. This UnqualifiedId instance will take ownership of the /// \p TemplateId and will free it on destruction. void setTemplateId(TemplateIdAnnotation *TemplateId); /// \brief Return the source range that covers this unqualified-id. SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(StartLocation, EndLocation); } SourceLocation getLocStart() const LLVM_READONLY { return StartLocation; } SourceLocation getLocEnd() const LLVM_READONLY { return EndLocation; } }; /// CachedTokens - A set of tokens that has been cached for later /// parsing. typedef SmallVector CachedTokens; /// DeclaratorChunk - One instance of this struct is used for each type in a /// declarator that is parsed. /// /// This is intended to be a small value object. struct DeclaratorChunk { enum { Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren } Kind; /// Loc - The place where this type was defined. SourceLocation Loc; /// EndLoc - If valid, the place where this chunck ends. SourceLocation EndLoc; struct TypeInfoCommon { AttributeList *AttrList; }; struct PointerTypeInfo : TypeInfoCommon { /// The type qualifiers: const/volatile/restrict. unsigned TypeQuals : 3; /// The location of the const-qualifier, if any. unsigned ConstQualLoc; /// The location of the volatile-qualifier, if any. unsigned VolatileQualLoc; /// The location of the restrict-qualifier, if any. unsigned RestrictQualLoc; void destroy() { } }; struct ReferenceTypeInfo : TypeInfoCommon { /// The type qualifier: restrict. [GNU] C++ extension bool HasRestrict : 1; /// True if this is an lvalue reference, false if it's an rvalue reference. bool LValueRef : 1; void destroy() { } }; struct ArrayTypeInfo : TypeInfoCommon { /// The type qualifiers for the array: const/volatile/restrict. unsigned TypeQuals : 3; /// True if this dimension included the 'static' keyword. bool hasStatic : 1; /// True if this dimension was [*]. In this case, NumElts is null. bool isStar : 1; /// This is the size of the array, or null if [] or [*] was specified. /// Since the parser is multi-purpose, and we don't want to impose a root /// expression class on all clients, NumElts is untyped. Expr *NumElts; void destroy() {} }; /// ParamInfo - An array of paraminfo objects is allocated whenever a function /// declarator is parsed. There are two interesting styles of arguments here: /// K&R-style identifier lists and parameter type lists. K&R-style identifier /// lists will have information about the identifier, but no type information. /// Parameter type lists will have type info (if the actions module provides /// it), but may have null identifier info: e.g. for 'void foo(int X, int)'. struct ParamInfo { IdentifierInfo *Ident; SourceLocation IdentLoc; Decl *Param; /// DefaultArgTokens - When the parameter's default argument /// cannot be parsed immediately (because it occurs within the /// declaration of a member function), it will be stored here as a /// sequence of tokens to be parsed once the class definition is /// complete. Non-NULL indicates that there is a default argument. CachedTokens *DefaultArgTokens; ParamInfo() {} ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Decl *param, CachedTokens *DefArgTokens = 0) : Ident(ident), IdentLoc(iloc), Param(param), DefaultArgTokens(DefArgTokens) {} }; struct TypeAndRange { ParsedType Ty; SourceRange Range; }; struct FunctionTypeInfo : TypeInfoCommon { /// hasPrototype - This is true if the function had at least one typed /// argument. If the function is () or (a,b,c), then it has no prototype, /// and is treated as a K&R-style function. unsigned hasPrototype : 1; /// isVariadic - If this function has a prototype, and if that /// proto ends with ',...)', this is true. When true, EllipsisLoc /// contains the location of the ellipsis. unsigned isVariadic : 1; /// \brief Whether the ref-qualifier (if any) is an lvalue reference. /// Otherwise, it's an rvalue reference. unsigned RefQualifierIsLValueRef : 1; /// The type qualifiers: const/volatile/restrict. /// The qualifier bitmask values are the same as in QualType. unsigned TypeQuals : 3; /// ExceptionSpecType - An ExceptionSpecificationType value. unsigned ExceptionSpecType : 3; /// DeleteArgInfo - If this is true, we need to delete[] ArgInfo. unsigned DeleteArgInfo : 1; /// When isVariadic is true, the location of the ellipsis in the source. unsigned EllipsisLoc; /// NumArgs - This is the number of formal arguments provided for the /// declarator. unsigned NumArgs; /// NumExceptions - This is the number of types in the dynamic-exception- /// decl, if the function has one. unsigned NumExceptions; /// \brief The location of the ref-qualifier, if any. /// /// If this is an invalid location, there is no ref-qualifier. unsigned RefQualifierLoc; /// \brief The location of the const-qualifier, if any. /// /// If this is an invalid location, there is no const-qualifier. unsigned ConstQualifierLoc; /// \brief The location of the volatile-qualifier, if any. /// /// If this is an invalid location, there is no volatile-qualifier. unsigned VolatileQualifierLoc; /// \brief The location of the 'mutable' qualifer in a lambda-declarator, if /// any. unsigned MutableLoc; /// \brief When ExceptionSpecType isn't EST_None or EST_Delayed, the /// location of the keyword introducing the spec. unsigned ExceptionSpecLoc; /// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that /// describe the arguments for this function declarator. This is null if /// there are no arguments specified. ParamInfo *ArgInfo; union { /// \brief Pointer to a new[]'d array of TypeAndRange objects that /// contain the types in the function's dynamic exception specification /// and their locations, if there is one. TypeAndRange *Exceptions; /// \brief Pointer to the expression in the noexcept-specifier of this /// function, if it has one. Expr *NoexceptExpr; - - /// \brief Pointer to the cached tokens for an exception-specification - /// that has not yet been parsed. - CachedTokens *ExceptionSpecTokens; }; /// TrailingReturnType - If this isn't null, it's the trailing return type /// specified. This is actually a ParsedType, but stored as void* to /// allow union storage. void *TrailingReturnType; /// freeArgs - reset the argument list to having zero arguments. This is /// used in various places for error recovery. void freeArgs() { if (DeleteArgInfo) { delete[] ArgInfo; DeleteArgInfo = false; } NumArgs = 0; } void destroy() { if (DeleteArgInfo) delete[] ArgInfo; if (getExceptionSpecType() == EST_Dynamic) delete[] Exceptions; - else if (getExceptionSpecType() == EST_Delayed) - delete ExceptionSpecTokens; } /// isKNRPrototype - Return true if this is a K&R style identifier list, /// like "void foo(a,b,c)". In a function definition, this will be followed /// by the argument type definitions. bool isKNRPrototype() const { return !hasPrototype && NumArgs != 0; } SourceLocation getEllipsisLoc() const { return SourceLocation::getFromRawEncoding(EllipsisLoc); } SourceLocation getExceptionSpecLoc() const { return SourceLocation::getFromRawEncoding(ExceptionSpecLoc); } /// \brief Retrieve the location of the ref-qualifier, if any. SourceLocation getRefQualifierLoc() const { return SourceLocation::getFromRawEncoding(RefQualifierLoc); } /// \brief Retrieve the location of the ref-qualifier, if any. SourceLocation getConstQualifierLoc() const { return SourceLocation::getFromRawEncoding(ConstQualifierLoc); } /// \brief Retrieve the location of the ref-qualifier, if any. SourceLocation getVolatileQualifierLoc() const { return SourceLocation::getFromRawEncoding(VolatileQualifierLoc); } /// \brief Retrieve the location of the 'mutable' qualifier, if any. SourceLocation getMutableLoc() const { return SourceLocation::getFromRawEncoding(MutableLoc); } /// \brief Determine whether this function declaration contains a /// ref-qualifier. bool hasRefQualifier() const { return getRefQualifierLoc().isValid(); } /// \brief Determine whether this lambda-declarator contains a 'mutable' /// qualifier. bool hasMutableQualifier() const { return getMutableLoc().isValid(); } /// \brief Get the type of exception specification this function has. ExceptionSpecificationType getExceptionSpecType() const { return static_cast(ExceptionSpecType); } }; struct BlockPointerTypeInfo : TypeInfoCommon { /// For now, sema will catch these as invalid. /// The type qualifiers: const/volatile/restrict. unsigned TypeQuals : 3; void destroy() { } }; struct MemberPointerTypeInfo : TypeInfoCommon { /// The type qualifiers: const/volatile/restrict. unsigned TypeQuals : 3; // CXXScopeSpec has a constructor, so it can't be a direct member. // So we need some pointer-aligned storage and a bit of trickery. union { void *Aligner; char Mem[sizeof(CXXScopeSpec)]; } ScopeMem; CXXScopeSpec &Scope() { return *reinterpret_cast(ScopeMem.Mem); } const CXXScopeSpec &Scope() const { return *reinterpret_cast(ScopeMem.Mem); } void destroy() { Scope().~CXXScopeSpec(); } }; union { TypeInfoCommon Common; PointerTypeInfo Ptr; ReferenceTypeInfo Ref; ArrayTypeInfo Arr; FunctionTypeInfo Fun; BlockPointerTypeInfo Cls; MemberPointerTypeInfo Mem; }; void destroy() { switch (Kind) { case DeclaratorChunk::Function: return Fun.destroy(); case DeclaratorChunk::Pointer: return Ptr.destroy(); case DeclaratorChunk::BlockPointer: return Cls.destroy(); case DeclaratorChunk::Reference: return Ref.destroy(); case DeclaratorChunk::Array: return Arr.destroy(); case DeclaratorChunk::MemberPointer: return Mem.destroy(); case DeclaratorChunk::Paren: return; } } /// getAttrs - If there are attributes applied to this declaratorchunk, return /// them. const AttributeList *getAttrs() const { return Common.AttrList; } AttributeList *&getAttrListRef() { return Common.AttrList; } /// getPointer - Return a DeclaratorChunk for a pointer. /// static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc, SourceLocation ConstQualLoc, SourceLocation VolatileQualLoc, SourceLocation RestrictQualLoc) { DeclaratorChunk I; I.Kind = Pointer; I.Loc = Loc; I.Ptr.TypeQuals = TypeQuals; I.Ptr.ConstQualLoc = ConstQualLoc.getRawEncoding(); I.Ptr.VolatileQualLoc = VolatileQualLoc.getRawEncoding(); I.Ptr.RestrictQualLoc = RestrictQualLoc.getRawEncoding(); I.Ptr.AttrList = 0; return I; } /// getReference - Return a DeclaratorChunk for a reference. /// static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc, bool lvalue) { DeclaratorChunk I; I.Kind = Reference; I.Loc = Loc; I.Ref.HasRestrict = (TypeQuals & DeclSpec::TQ_restrict) != 0; I.Ref.LValueRef = lvalue; I.Ref.AttrList = 0; return I; } /// getArray - Return a DeclaratorChunk for an array. /// static DeclaratorChunk getArray(unsigned TypeQuals, bool isStatic, bool isStar, Expr *NumElts, SourceLocation LBLoc, SourceLocation RBLoc) { DeclaratorChunk I; I.Kind = Array; I.Loc = LBLoc; I.EndLoc = RBLoc; I.Arr.AttrList = 0; I.Arr.TypeQuals = TypeQuals; I.Arr.hasStatic = isStatic; I.Arr.isStar = isStar; I.Arr.NumElts = NumElts; return I; } /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. static DeclaratorChunk getFunction(bool hasProto, bool isVariadic, SourceLocation EllipsisLoc, ParamInfo *ArgInfo, unsigned NumArgs, unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, SourceLocation ConstQualifierLoc, SourceLocation VolatileQualifierLoc, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, SourceLocation ESpecLoc, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, - CachedTokens *ExceptionSpecTokens, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, ParsedType TrailingReturnType = ParsedType()); /// getBlockPointer - Return a DeclaratorChunk for a block. /// static DeclaratorChunk getBlockPointer(unsigned TypeQuals, SourceLocation Loc) { DeclaratorChunk I; I.Kind = BlockPointer; I.Loc = Loc; I.Cls.TypeQuals = TypeQuals; I.Cls.AttrList = 0; return I; } static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS, unsigned TypeQuals, SourceLocation Loc) { DeclaratorChunk I; I.Kind = MemberPointer; I.Loc = Loc; I.Mem.TypeQuals = TypeQuals; I.Mem.AttrList = 0; new (I.Mem.ScopeMem.Mem) CXXScopeSpec(SS); return I; } /// getParen - Return a DeclaratorChunk for a paren. /// static DeclaratorChunk getParen(SourceLocation LParenLoc, SourceLocation RParenLoc) { DeclaratorChunk I; I.Kind = Paren; I.Loc = LParenLoc; I.EndLoc = RParenLoc; I.Common.AttrList = 0; return I; } }; /// \brief Described the kind of function definition (if any) provided for /// a function. enum FunctionDefinitionKind { FDK_Declaration, FDK_Definition, FDK_Defaulted, FDK_Deleted }; /// Declarator - Information about one declarator, including the parsed type /// information and the identifier. When the declarator is fully formed, this /// is turned into the appropriate Decl object. /// /// Declarators come in two types: normal declarators and abstract declarators. /// Abstract declarators are used when parsing types, and don't have an /// identifier. Normal declarators do have ID's. /// /// Instances of this class should be a transient object that lives on the /// stack, not objects that are allocated in large quantities on the heap. class Declarator { public: enum TheContext { FileContext, // File scope declaration. PrototypeContext, // Within a function prototype. ObjCResultContext, // An ObjC method result type. ObjCParameterContext,// An ObjC method parameter type. KNRTypeListContext, // K&R type definition list for formals. TypeNameContext, // Abstract declarator for types. MemberContext, // Struct/Union field. BlockContext, // Declaration within a block in a function. ForContext, // Declaration within first part of a for loop. ConditionContext, // Condition declaration in a C++ if/switch/while/for. TemplateParamContext,// Within a template parameter list. CXXNewContext, // C++ new-expression. CXXCatchContext, // C++ catch exception-declaration ObjCCatchContext, // Objective-C catch exception-declaration BlockLiteralContext, // Block literal declarator. LambdaExprContext, // Lambda-expression declarator. TrailingReturnContext, // C++11 trailing-type-specifier. TemplateTypeArgContext, // Template type argument. AliasDeclContext, // C++11 alias-declaration. AliasTemplateContext // C++11 alias-declaration template. }; private: const DeclSpec &DS; CXXScopeSpec SS; UnqualifiedId Name; SourceRange Range; /// Context - Where we are parsing this declarator. /// TheContext Context; /// DeclTypeInfo - This holds each type that the declarator includes as it is /// parsed. This is pushed from the identifier out, which means that element /// #0 will be the most closely bound to the identifier, and /// DeclTypeInfo.back() will be the least closely bound. SmallVector DeclTypeInfo; /// InvalidType - Set by Sema::GetTypeForDeclarator(). bool InvalidType : 1; /// GroupingParens - Set by Parser::ParseParenDeclarator(). bool GroupingParens : 1; /// FunctionDefinition - Is this Declarator for a function or member /// definition and, if so, what kind? /// /// Actually a FunctionDefinitionKind. unsigned FunctionDefinition : 2; // Redeclaration - Is this Declarator is a redeclaration. bool Redeclaration : 1; /// Attrs - Attributes. ParsedAttributes Attrs; /// AsmLabel - The asm label, if specified. Expr *AsmLabel; /// InlineParams - This is a local array used for the first function decl /// chunk to avoid going to the heap for the common case when we have one /// function chunk in the declarator. DeclaratorChunk::ParamInfo InlineParams[16]; bool InlineParamsUsed; /// Extension - true if the declaration is preceded by __extension__. bool Extension : 1; /// \brief If this is the second or subsequent declarator in this declaration, /// the location of the comma before this declarator. SourceLocation CommaLoc; /// \brief If provided, the source location of the ellipsis used to describe /// this declarator as a parameter pack. SourceLocation EllipsisLoc; friend struct DeclaratorChunk; public: Declarator(const DeclSpec &ds, TheContext C) : DS(ds), Range(ds.getSourceRange()), Context(C), InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), GroupingParens(false), FunctionDefinition(FDK_Declaration), Redeclaration(false), Attrs(ds.getAttributePool().getFactory()), AsmLabel(0), InlineParamsUsed(false), Extension(false) { } ~Declarator() { clear(); } /// getDeclSpec - Return the declaration-specifier that this declarator was /// declared with. const DeclSpec &getDeclSpec() const { return DS; } /// getMutableDeclSpec - Return a non-const version of the DeclSpec. This /// should be used with extreme care: declspecs can often be shared between /// multiple declarators, so mutating the DeclSpec affects all of the /// Declarators. This should only be done when the declspec is known to not /// be shared or when in error recovery etc. DeclSpec &getMutableDeclSpec() { return const_cast(DS); } AttributePool &getAttributePool() const { return Attrs.getPool(); } /// getCXXScopeSpec - Return the C++ scope specifier (global scope or /// nested-name-specifier) that is part of the declarator-id. const CXXScopeSpec &getCXXScopeSpec() const { return SS; } CXXScopeSpec &getCXXScopeSpec() { return SS; } /// \brief Retrieve the name specified by this declarator. UnqualifiedId &getName() { return Name; } TheContext getContext() const { return Context; } bool isPrototypeContext() const { return (Context == PrototypeContext || Context == ObjCParameterContext || Context == ObjCResultContext); } /// getSourceRange - Get the source range that spans this declarator. const SourceRange &getSourceRange() const LLVM_READONLY { return Range; } SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } void SetSourceRange(SourceRange R) { Range = R; } /// SetRangeBegin - Set the start of the source range to Loc, unless it's /// invalid. void SetRangeBegin(SourceLocation Loc) { if (!Loc.isInvalid()) Range.setBegin(Loc); } /// SetRangeEnd - Set the end of the source range to Loc, unless it's invalid. void SetRangeEnd(SourceLocation Loc) { if (!Loc.isInvalid()) Range.setEnd(Loc); } /// ExtendWithDeclSpec - Extend the declarator source range to include the /// given declspec, unless its location is invalid. Adopts the range start if /// the current range start is invalid. void ExtendWithDeclSpec(const DeclSpec &DS) { const SourceRange &SR = DS.getSourceRange(); if (Range.getBegin().isInvalid()) Range.setBegin(SR.getBegin()); if (!SR.getEnd().isInvalid()) Range.setEnd(SR.getEnd()); } /// clear - Reset the contents of this Declarator. void clear() { SS.clear(); Name.clear(); Range = DS.getSourceRange(); for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) DeclTypeInfo[i].destroy(); DeclTypeInfo.clear(); Attrs.clear(); AsmLabel = 0; InlineParamsUsed = false; CommaLoc = SourceLocation(); EllipsisLoc = SourceLocation(); } /// mayOmitIdentifier - Return true if the identifier is either optional or /// not allowed. This is true for typenames, prototypes, and template /// parameter lists. bool mayOmitIdentifier() const { switch (Context) { case FileContext: case KNRTypeListContext: case MemberContext: case BlockContext: case ForContext: case ConditionContext: return false; case TypeNameContext: case AliasDeclContext: case AliasTemplateContext: case PrototypeContext: case ObjCParameterContext: case ObjCResultContext: case TemplateParamContext: case CXXNewContext: case CXXCatchContext: case ObjCCatchContext: case BlockLiteralContext: case LambdaExprContext: case TemplateTypeArgContext: case TrailingReturnContext: return true; } llvm_unreachable("unknown context kind!"); } /// mayHaveIdentifier - Return true if the identifier is either optional or /// required. This is true for normal declarators and prototypes, but not /// typenames. bool mayHaveIdentifier() const { switch (Context) { case FileContext: case KNRTypeListContext: case MemberContext: case BlockContext: case ForContext: case ConditionContext: case PrototypeContext: case TemplateParamContext: case CXXCatchContext: case ObjCCatchContext: return true; case TypeNameContext: case CXXNewContext: case AliasDeclContext: case AliasTemplateContext: case ObjCParameterContext: case ObjCResultContext: case BlockLiteralContext: case LambdaExprContext: case TemplateTypeArgContext: case TrailingReturnContext: return false; } llvm_unreachable("unknown context kind!"); } /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be /// followed by a C++ direct initializer, e.g. "int x(1);". bool mayBeFollowedByCXXDirectInit() const { if (hasGroupingParens()) return false; if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) return false; if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern && Context != FileContext) return false; // Special names can't have direct initializers. if (Name.getKind() != UnqualifiedId::IK_Identifier) return false; switch (Context) { case FileContext: case BlockContext: case ForContext: return true; case ConditionContext: // This may not be followed by a direct initializer, but it can't be a // function declaration either, and we'd prefer to perform a tentative // parse in order to produce the right diagnostic. return true; case KNRTypeListContext: case MemberContext: case PrototypeContext: case ObjCParameterContext: case ObjCResultContext: case TemplateParamContext: case CXXCatchContext: case ObjCCatchContext: case TypeNameContext: case CXXNewContext: case AliasDeclContext: case AliasTemplateContext: case BlockLiteralContext: case LambdaExprContext: case TemplateTypeArgContext: case TrailingReturnContext: return false; } llvm_unreachable("unknown context kind!"); } /// isPastIdentifier - Return true if we have parsed beyond the point where /// the bool isPastIdentifier() const { return Name.isValid(); } /// hasName - Whether this declarator has a name, which might be an /// identifier (accessible via getIdentifier()) or some kind of /// special C++ name (constructor, destructor, etc.). bool hasName() const { return Name.getKind() != UnqualifiedId::IK_Identifier || Name.Identifier; } IdentifierInfo *getIdentifier() const { if (Name.getKind() == UnqualifiedId::IK_Identifier) return Name.Identifier; return 0; } SourceLocation getIdentifierLoc() const { return Name.StartLocation; } /// \brief Set the name of this declarator to be the given identifier. void SetIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) { Name.setIdentifier(Id, IdLoc); } /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to /// EndLoc, which should be the last token of the chunk. void AddTypeInfo(const DeclaratorChunk &TI, ParsedAttributes &attrs, SourceLocation EndLoc) { DeclTypeInfo.push_back(TI); DeclTypeInfo.back().getAttrListRef() = attrs.getList(); getAttributePool().takeAllFrom(attrs.getPool()); if (!EndLoc.isInvalid()) SetRangeEnd(EndLoc); } /// AddInnermostTypeInfo - Add a new innermost chunk to this declarator. void AddInnermostTypeInfo(const DeclaratorChunk &TI) { DeclTypeInfo.insert(DeclTypeInfo.begin(), TI); } /// getNumTypeObjects() - Return the number of types applied to this /// declarator. unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); } /// Return the specified TypeInfo from this declarator. TypeInfo #0 is /// closest to the identifier. const DeclaratorChunk &getTypeObject(unsigned i) const { assert(i < DeclTypeInfo.size() && "Invalid type chunk"); return DeclTypeInfo[i]; } DeclaratorChunk &getTypeObject(unsigned i) { assert(i < DeclTypeInfo.size() && "Invalid type chunk"); return DeclTypeInfo[i]; } void DropFirstTypeObject() { assert(!DeclTypeInfo.empty() && "No type chunks to drop."); DeclTypeInfo.front().destroy(); DeclTypeInfo.erase(DeclTypeInfo.begin()); } /// isArrayOfUnknownBound - This method returns true if the declarator /// is a declarator for an array of unknown bound (looking through /// parentheses). bool isArrayOfUnknownBound() const { for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { switch (DeclTypeInfo[i].Kind) { case DeclaratorChunk::Paren: continue; case DeclaratorChunk::Function: case DeclaratorChunk::Pointer: case DeclaratorChunk::Reference: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: return false; case DeclaratorChunk::Array: return !DeclTypeInfo[i].Arr.NumElts; } llvm_unreachable("Invalid type chunk"); } return false; } /// isFunctionDeclarator - This method returns true if the declarator /// is a function declarator (looking through parentheses). /// If true is returned, then the reference type parameter idx is /// assigned with the index of the declaration chunk. bool isFunctionDeclarator(unsigned& idx) const { for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { switch (DeclTypeInfo[i].Kind) { case DeclaratorChunk::Function: idx = i; return true; case DeclaratorChunk::Paren: continue; case DeclaratorChunk::Pointer: case DeclaratorChunk::Reference: case DeclaratorChunk::Array: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: return false; } llvm_unreachable("Invalid type chunk"); } return false; } /// isFunctionDeclarator - Once this declarator is fully parsed and formed, /// this method returns true if the identifier is a function declarator /// (looking through parentheses). bool isFunctionDeclarator() const { unsigned index; return isFunctionDeclarator(index); } /// getFunctionTypeInfo - Retrieves the function type info object /// (looking through parentheses). DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() { assert(isFunctionDeclarator() && "Not a function declarator!"); unsigned index = 0; isFunctionDeclarator(index); return DeclTypeInfo[index].Fun; } /// getFunctionTypeInfo - Retrieves the function type info object /// (looking through parentheses). const DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() const { return const_cast(this)->getFunctionTypeInfo(); } /// \brief Determine whether the declaration that will be produced from /// this declaration will be a function. /// /// A declaration can declare a function even if the declarator itself /// isn't a function declarator, if the type specifier refers to a function /// type. This routine checks for both cases. bool isDeclarationOfFunction() const; /// takeAttributes - Takes attributes from the given parsed-attributes /// set and add them to this declarator. /// /// These examples both add 3 attributes to "var": /// short int var __attribute__((aligned(16),common,deprecated)); /// short int x, __attribute__((aligned(16)) var /// __attribute__((common,deprecated)); /// /// Also extends the range of the declarator. void takeAttributes(ParsedAttributes &attrs, SourceLocation lastLoc) { Attrs.takeAllFrom(attrs); if (!lastLoc.isInvalid()) SetRangeEnd(lastLoc); } const AttributeList *getAttributes() const { return Attrs.getList(); } AttributeList *getAttributes() { return Attrs.getList(); } AttributeList *&getAttrListRef() { return Attrs.getListRef(); } /// hasAttributes - do we contain any attributes? bool hasAttributes() const { if (getAttributes() || getDeclSpec().hasAttributes()) return true; for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i) if (getTypeObject(i).getAttrs()) return true; return false; } void setAsmLabel(Expr *E) { AsmLabel = E; } Expr *getAsmLabel() const { return AsmLabel; } void setExtension(bool Val = true) { Extension = Val; } bool getExtension() const { return Extension; } void setInvalidType(bool Val = true) { InvalidType = Val; } bool isInvalidType() const { return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; } void setGroupingParens(bool flag) { GroupingParens = flag; } bool hasGroupingParens() const { return GroupingParens; } bool isFirstDeclarator() const { return !CommaLoc.isValid(); } SourceLocation getCommaLoc() const { return CommaLoc; } void setCommaLoc(SourceLocation CL) { CommaLoc = CL; } bool hasEllipsis() const { return EllipsisLoc.isValid(); } SourceLocation getEllipsisLoc() const { return EllipsisLoc; } void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; } void setFunctionDefinitionKind(FunctionDefinitionKind Val) { FunctionDefinition = Val; } bool isFunctionDefinition() const { return getFunctionDefinitionKind() != FDK_Declaration; } FunctionDefinitionKind getFunctionDefinitionKind() const { return (FunctionDefinitionKind)FunctionDefinition; } void setRedeclaration(bool Val) { Redeclaration = Val; } bool isRedeclaration() const { return Redeclaration; } }; /// FieldDeclarator - This little struct is used to capture information about /// structure field declarators, which is basically just a bitfield size. struct FieldDeclarator { Declarator D; Expr *BitfieldSize; explicit FieldDeclarator(DeclSpec &DS) : D(DS, Declarator::MemberContext) { BitfieldSize = 0; } }; /// VirtSpecifiers - Represents a C++0x virt-specifier-seq. class VirtSpecifiers { public: enum Specifier { VS_None = 0, VS_Override = 1, VS_Final = 2 }; VirtSpecifiers() : Specifiers(0) { } bool SetSpecifier(Specifier VS, SourceLocation Loc, const char *&PrevSpec); bool isOverrideSpecified() const { return Specifiers & VS_Override; } SourceLocation getOverrideLoc() const { return VS_overrideLoc; } bool isFinalSpecified() const { return Specifiers & VS_Final; } SourceLocation getFinalLoc() const { return VS_finalLoc; } void clear() { Specifiers = 0; } static const char *getSpecifierName(Specifier VS); SourceLocation getLastLocation() const { return LastLocation; } private: unsigned Specifiers; SourceLocation VS_overrideLoc, VS_finalLoc; SourceLocation LastLocation; }; /// LambdaCapture - An individual capture in a lambda introducer. struct LambdaCapture { LambdaCaptureKind Kind; SourceLocation Loc; IdentifierInfo* Id; SourceLocation EllipsisLoc; LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc, IdentifierInfo* Id = 0, SourceLocation EllipsisLoc = SourceLocation()) : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc) {} }; /// LambdaIntroducer - Represents a complete lambda introducer. struct LambdaIntroducer { SourceRange Range; SourceLocation DefaultLoc; LambdaCaptureDefault Default; llvm::SmallVector Captures; LambdaIntroducer() : Default(LCD_None) {} /// addCapture - Append a capture in a lambda introducer. void addCapture(LambdaCaptureKind Kind, SourceLocation Loc, IdentifierInfo* Id = 0, SourceLocation EllipsisLoc = SourceLocation()) { Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc)); } }; } // end namespace clang #endif Index: vendor/clang/dist/include/clang/Sema/Initialization.h =================================================================== --- vendor/clang/dist/include/clang/Sema/Initialization.h (revision 235808) +++ vendor/clang/dist/include/clang/Sema/Initialization.h (revision 235809) @@ -1,999 +1,1001 @@ //===--- Initialization.h - Semantic Analysis for Initializers --*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file provides supporting data types for initialization of objects. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_INITIALIZATION_H #define LLVM_CLANG_SEMA_INITIALIZATION_H #include "clang/Sema/Ownership.h" #include "clang/Sema/Overload.h" #include "clang/AST/Type.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include namespace clang { class CXXBaseSpecifier; class DeclaratorDecl; class DeclaratorInfo; class FieldDecl; class FunctionDecl; class ParmVarDecl; class Sema; class TypeLoc; class VarDecl; /// \brief Describes an entity that is being initialized. class InitializedEntity { public: /// \brief Specifies the kind of entity being initialized. enum EntityKind { /// \brief The entity being initialized is a variable. EK_Variable, /// \brief The entity being initialized is a function parameter. EK_Parameter, /// \brief The entity being initialized is the result of a function call. EK_Result, /// \brief The entity being initialized is an exception object that /// is being thrown. EK_Exception, /// \brief The entity being initialized is a non-static data member /// subobject. EK_Member, /// \brief The entity being initialized is an element of an array. EK_ArrayElement, /// \brief The entity being initialized is an object (or array of /// objects) allocated via new. EK_New, /// \brief The entity being initialized is a temporary object. EK_Temporary, /// \brief The entity being initialized is a base member subobject. EK_Base, /// \brief The initialization is being done by a delegating constructor. EK_Delegating, /// \brief The entity being initialized is an element of a vector. /// or vector. EK_VectorElement, /// \brief The entity being initialized is a field of block descriptor for /// the copied-in c++ object. EK_BlockElement, /// \brief The entity being initialized is the real or imaginary part of a /// complex number. EK_ComplexElement, /// \brief The entity being initialized is the field that captures a /// variable in a lambda. EK_LambdaCapture }; private: /// \brief The kind of entity being initialized. EntityKind Kind; /// \brief If non-NULL, the parent entity in which this /// initialization occurs. const InitializedEntity *Parent; /// \brief The type of the object or reference being initialized. QualType Type; union { /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or /// FieldDecl, respectively. DeclaratorDecl *VariableOrMember; /// \brief When Kind == EK_Parameter, the ParmVarDecl, with the /// low bit indicating whether the parameter is "consumed". uintptr_t Parameter; /// \brief When Kind == EK_Temporary, the type source information for /// the temporary. TypeSourceInfo *TypeInfo; struct { /// \brief When Kind == EK_Result, EK_Exception, EK_New, the /// location of the 'return', 'throw', or 'new' keyword, /// respectively. When Kind == EK_Temporary, the location where /// the temporary is being created. unsigned Location; /// \brief Whether the entity being initialized may end up using the /// named return value optimization (NRVO). bool NRVO; } LocAndNRVO; /// \brief When Kind == EK_Base, the base specifier that provides the /// base class. The lower bit specifies whether the base is an inherited /// virtual base. uintptr_t Base; /// \brief When Kind == EK_ArrayElement, EK_VectorElement, or /// EK_ComplexElement, the index of the array or vector element being /// initialized. unsigned Index; struct { /// \brief The variable being captured by an EK_LambdaCapture. VarDecl *Var; /// \brief The source location at which the capture occurs. unsigned Location; } Capture; }; InitializedEntity() { } /// \brief Create the initialization entity for a variable. InitializedEntity(VarDecl *Var) : Kind(EK_Variable), Parent(0), Type(Var->getType()), VariableOrMember(Var) { } /// \brief Create the initialization entity for the result of a /// function, throwing an object, performing an explicit cast, or /// initializing a parameter for which there is no declaration. InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, bool NRVO = false) : Kind(Kind), Parent(0), Type(Type) { LocAndNRVO.Location = Loc.getRawEncoding(); LocAndNRVO.NRVO = NRVO; } /// \brief Create the initialization entity for a member subobject. InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent) : Kind(EK_Member), Parent(Parent), Type(Member->getType()), VariableOrMember(Member) { } /// \brief Create the initialization entity for an array element. InitializedEntity(ASTContext &Context, unsigned Index, const InitializedEntity &Parent); /// \brief Create the initialization entity for a lambda capture. InitializedEntity(VarDecl *Var, FieldDecl *Field, SourceLocation Loc) : Kind(EK_LambdaCapture), Parent(0), Type(Field->getType()) { Capture.Var = Var; Capture.Location = Loc.getRawEncoding(); } public: /// \brief Create the initialization entity for a variable. static InitializedEntity InitializeVariable(VarDecl *Var) { return InitializedEntity(Var); } /// \brief Create the initialization entity for a parameter. static InitializedEntity InitializeParameter(ASTContext &Context, ParmVarDecl *Parm) { bool Consumed = (Context.getLangOpts().ObjCAutoRefCount && Parm->hasAttr()); InitializedEntity Entity; Entity.Kind = EK_Parameter; Entity.Type = Context.getVariableArrayDecayedType( Parm->getType().getUnqualifiedType()); Entity.Parent = 0; Entity.Parameter = (static_cast(Consumed) | reinterpret_cast(Parm)); return Entity; } /// \brief Create the initialization entity for a parameter that is /// only known by its type. static InitializedEntity InitializeParameter(ASTContext &Context, QualType Type, bool Consumed) { InitializedEntity Entity; Entity.Kind = EK_Parameter; Entity.Type = Context.getVariableArrayDecayedType(Type); Entity.Parent = 0; Entity.Parameter = (Consumed); return Entity; } /// \brief Create the initialization entity for the result of a function. static InitializedEntity InitializeResult(SourceLocation ReturnLoc, QualType Type, bool NRVO) { return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); } static InitializedEntity InitializeBlock(SourceLocation BlockVarLoc, QualType Type, bool NRVO) { return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO); } /// \brief Create the initialization entity for an exception object. static InitializedEntity InitializeException(SourceLocation ThrowLoc, QualType Type, bool NRVO) { return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO); } /// \brief Create the initialization entity for an object allocated via new. static InitializedEntity InitializeNew(SourceLocation NewLoc, QualType Type) { return InitializedEntity(EK_New, NewLoc, Type); } /// \brief Create the initialization entity for a temporary. static InitializedEntity InitializeTemporary(QualType Type) { - return InitializedEntity(EK_Temporary, SourceLocation(), Type); + InitializedEntity Result(EK_Temporary, SourceLocation(), Type); + Result.TypeInfo = 0; + return Result; } /// \brief Create the initialization entity for a temporary. static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) { InitializedEntity Result(EK_Temporary, SourceLocation(), TypeInfo->getType()); Result.TypeInfo = TypeInfo; return Result; } /// \brief Create the initialization entity for a base class subobject. static InitializedEntity InitializeBase(ASTContext &Context, CXXBaseSpecifier *Base, bool IsInheritedVirtualBase); /// \brief Create the initialization entity for a delegated constructor. static InitializedEntity InitializeDelegation(QualType Type) { return InitializedEntity(EK_Delegating, SourceLocation(), Type); } /// \brief Create the initialization entity for a member subobject. static InitializedEntity InitializeMember(FieldDecl *Member, const InitializedEntity *Parent = 0) { return InitializedEntity(Member, Parent); } /// \brief Create the initialization entity for a member subobject. static InitializedEntity InitializeMember(IndirectFieldDecl *Member, const InitializedEntity *Parent = 0) { return InitializedEntity(Member->getAnonField(), Parent); } /// \brief Create the initialization entity for an array element. static InitializedEntity InitializeElement(ASTContext &Context, unsigned Index, const InitializedEntity &Parent) { return InitializedEntity(Context, Index, Parent); } /// \brief Create the initialization entity for a lambda capture. static InitializedEntity InitializeLambdaCapture(VarDecl *Var, FieldDecl *Field, SourceLocation Loc) { return InitializedEntity(Var, Field, Loc); } /// \brief Determine the kind of initialization. EntityKind getKind() const { return Kind; } /// \brief Retrieve the parent of the entity being initialized, when /// the initialization itself is occurring within the context of a /// larger initialization. const InitializedEntity *getParent() const { return Parent; } /// \brief Retrieve type being initialized. QualType getType() const { return Type; } /// \brief Retrieve complete type-source information for the object being /// constructed, if known. TypeSourceInfo *getTypeSourceInfo() const { if (Kind == EK_Temporary) return TypeInfo; return 0; } /// \brief Retrieve the name of the entity being initialized. DeclarationName getName() const; /// \brief Retrieve the variable, parameter, or field being /// initialized. DeclaratorDecl *getDecl() const; /// \brief Determine whether this initialization allows the named return /// value optimization, which also applies to thrown objects. bool allowsNRVO() const; /// \brief Determine whether this initialization consumes the /// parameter. bool isParameterConsumed() const { assert(getKind() == EK_Parameter && "Not a parameter"); return (Parameter & 1); } /// \brief Retrieve the base specifier. CXXBaseSpecifier *getBaseSpecifier() const { assert(getKind() == EK_Base && "Not a base specifier"); return reinterpret_cast(Base & ~0x1); } /// \brief Return whether the base is an inherited virtual base. bool isInheritedVirtualBase() const { assert(getKind() == EK_Base && "Not a base specifier"); return Base & 0x1; } /// \brief Determine the location of the 'return' keyword when initializing /// the result of a function call. SourceLocation getReturnLoc() const { assert(getKind() == EK_Result && "No 'return' location!"); return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } /// \brief Determine the location of the 'throw' keyword when initializing /// an exception object. SourceLocation getThrowLoc() const { assert(getKind() == EK_Exception && "No 'throw' location!"); return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); } /// \brief If this is already the initializer for an array or vector /// element, sets the element index. void setElementIndex(unsigned Index) { assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement || getKind() == EK_ComplexElement); this->Index = Index; } /// \brief Retrieve the variable for a captured variable in a lambda. VarDecl *getCapturedVar() const { assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); return Capture.Var; } /// \brief Determine the location of the capture when initializing /// field from a captured variable in a lambda. SourceLocation getCaptureLoc() const { assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); return SourceLocation::getFromRawEncoding(Capture.Location); } }; /// \brief Describes the kind of initialization being performed, along with /// location information for tokens related to the initialization (equal sign, /// parentheses). class InitializationKind { public: /// \brief The kind of initialization being performed. enum InitKind { IK_Direct, ///< Direct initialization IK_DirectList, ///< Direct list-initialization IK_Copy, ///< Copy initialization IK_Default, ///< Default initialization IK_Value ///< Value initialization }; private: /// \brief The context of the initialization. enum InitContext { IC_Normal, ///< Normal context IC_ExplicitConvs, ///< Normal context, but allows explicit conversion funcs IC_Implicit, ///< Implicit context (value initialization) IC_StaticCast, ///< Static cast context IC_CStyleCast, ///< C-style cast context IC_FunctionalCast ///< Functional cast context }; /// \brief The kind of initialization being performed. InitKind Kind : 8; /// \brief The context of the initialization. InitContext Context : 8; /// \brief The source locations involved in the initialization. SourceLocation Locations[3]; InitializationKind(InitKind Kind, InitContext Context, SourceLocation Loc1, SourceLocation Loc2, SourceLocation Loc3) : Kind(Kind), Context(Context) { Locations[0] = Loc1; Locations[1] = Loc2; Locations[2] = Loc3; } public: /// \brief Create a direct initialization. static InitializationKind CreateDirect(SourceLocation InitLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { return InitializationKind(IK_Direct, IC_Normal, InitLoc, LParenLoc, RParenLoc); } static InitializationKind CreateDirectList(SourceLocation InitLoc) { return InitializationKind(IK_DirectList, IC_Normal, InitLoc, InitLoc, InitLoc); } /// \brief Create a direct initialization due to a cast that isn't a C-style /// or functional cast. static InitializationKind CreateCast(SourceRange TypeRange) { return InitializationKind(IK_Direct, IC_StaticCast, TypeRange.getBegin(), TypeRange.getBegin(), TypeRange.getEnd()); } /// \brief Create a direct initialization for a C-style cast. static InitializationKind CreateCStyleCast(SourceLocation StartLoc, SourceRange TypeRange, bool InitList) { // C++ cast syntax doesn't permit init lists, but C compound literals are // exactly that. return InitializationKind(InitList ? IK_DirectList : IK_Direct, IC_CStyleCast, StartLoc, TypeRange.getBegin(), TypeRange.getEnd()); } /// \brief Create a direct initialization for a functional cast. static InitializationKind CreateFunctionalCast(SourceRange TypeRange, bool InitList) { return InitializationKind(InitList ? IK_DirectList : IK_Direct, IC_FunctionalCast, TypeRange.getBegin(), TypeRange.getBegin(), TypeRange.getEnd()); } /// \brief Create a copy initialization. static InitializationKind CreateCopy(SourceLocation InitLoc, SourceLocation EqualLoc, bool AllowExplicitConvs = false) { return InitializationKind(IK_Copy, AllowExplicitConvs? IC_ExplicitConvs : IC_Normal, InitLoc, EqualLoc, EqualLoc); } /// \brief Create a default initialization. static InitializationKind CreateDefault(SourceLocation InitLoc) { return InitializationKind(IK_Default, IC_Normal, InitLoc, InitLoc, InitLoc); } /// \brief Create a value initialization. static InitializationKind CreateValue(SourceLocation InitLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, bool isImplicit = false) { return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal, InitLoc, LParenLoc, RParenLoc); } /// \brief Determine the initialization kind. InitKind getKind() const { return Kind; } /// \brief Determine whether this initialization is an explicit cast. bool isExplicitCast() const { return Context >= IC_StaticCast; } /// \brief Determine whether this initialization is a C-style cast. bool isCStyleOrFunctionalCast() const { return Context >= IC_CStyleCast; } /// \brief Determine whether this is a C-style cast. bool isCStyleCast() const { return Context == IC_CStyleCast; } /// \brief Determine whether this is a functional-style cast. bool isFunctionalCast() const { return Context == IC_FunctionalCast; } /// \brief Determine whether this initialization is an implicit /// value-initialization, e.g., as occurs during aggregate /// initialization. bool isImplicitValueInit() const { return Context == IC_Implicit; } /// \brief Retrieve the location at which initialization is occurring. SourceLocation getLocation() const { return Locations[0]; } /// \brief Retrieve the source range that covers the initialization. SourceRange getRange() const { return SourceRange(Locations[0], Locations[2]); } /// \brief Retrieve the location of the equal sign for copy initialization /// (if present). SourceLocation getEqualLoc() const { assert(Kind == IK_Copy && "Only copy initialization has an '='"); return Locations[1]; } bool isCopyInit() const { return Kind == IK_Copy; } /// \brief Retrieve whether this initialization allows the use of explicit /// constructors. bool AllowExplicit() const { return !isCopyInit(); } /// \brief Retrieve whether this initialization allows the use of explicit /// conversion functions. bool allowExplicitConversionFunctions() const { return !isCopyInit() || Context == IC_ExplicitConvs; } /// \brief Retrieve the source range containing the locations of the open /// and closing parentheses for value and direct initializations. SourceRange getParenRange() const { assert((Kind == IK_Direct || Kind == IK_Value) && "Only direct- and value-initialization have parentheses"); return SourceRange(Locations[1], Locations[2]); } }; /// \brief Describes the sequence of initializations required to initialize /// a given object or reference with a set of arguments. class InitializationSequence { public: /// \brief Describes the kind of initialization sequence computed. enum SequenceKind { /// \brief A failed initialization sequence. The failure kind tells what /// happened. FailedSequence = 0, /// \brief A dependent initialization, which could not be /// type-checked due to the presence of dependent types or /// dependently-typed expressions. DependentSequence, /// \brief A normal sequence. NormalSequence }; /// \brief Describes the kind of a particular step in an initialization /// sequence. enum StepKind { /// \brief Resolve the address of an overloaded function to a specific /// function declaration. SK_ResolveAddressOfOverloadedFunction, /// \brief Perform a derived-to-base cast, producing an rvalue. SK_CastDerivedToBaseRValue, /// \brief Perform a derived-to-base cast, producing an xvalue. SK_CastDerivedToBaseXValue, /// \brief Perform a derived-to-base cast, producing an lvalue. SK_CastDerivedToBaseLValue, /// \brief Reference binding to an lvalue. SK_BindReference, /// \brief Reference binding to a temporary. SK_BindReferenceToTemporary, /// \brief An optional copy of a temporary object to another /// temporary object, which is permitted (but not required) by /// C++98/03 but not C++0x. SK_ExtraneousCopyToTemporary, /// \brief Perform a user-defined conversion, either via a conversion /// function or via a constructor. SK_UserConversion, /// \brief Perform a qualification conversion, producing an rvalue. SK_QualificationConversionRValue, /// \brief Perform a qualification conversion, producing an xvalue. SK_QualificationConversionXValue, /// \brief Perform a qualification conversion, producing an lvalue. SK_QualificationConversionLValue, /// \brief Perform an implicit conversion sequence. SK_ConversionSequence, /// \brief Perform list-initialization without a constructor SK_ListInitialization, /// \brief Perform list-initialization with a constructor. SK_ListConstructorCall, /// \brief Unwrap the single-element initializer list for a reference. SK_UnwrapInitList, /// \brief Rewrap the single-element initializer list for a reference. SK_RewrapInitList, /// \brief Perform initialization via a constructor. SK_ConstructorInitialization, /// \brief Zero-initialize the object SK_ZeroInitialization, /// \brief C assignment SK_CAssignment, /// \brief Initialization by string SK_StringInit, /// \brief An initialization that "converts" an Objective-C object /// (not a point to an object) to another Objective-C object type. SK_ObjCObjectConversion, /// \brief Array initialization (from an array rvalue). /// This is a GNU C extension. SK_ArrayInit, /// \brief Array initialization from a parenthesized initializer list. /// This is a GNU C++ extension. SK_ParenthesizedArrayInit, /// \brief Pass an object by indirect copy-and-restore. SK_PassByIndirectCopyRestore, /// \brief Pass an object by indirect restore. SK_PassByIndirectRestore, /// \brief Produce an Objective-C object pointer. SK_ProduceObjCObject, /// \brief Construct a std::initializer_list from an initializer list. SK_StdInitializerList }; /// \brief A single step in the initialization sequence. class Step { public: /// \brief The kind of conversion or initialization step we are taking. StepKind Kind; // \brief The type that results from this initialization. QualType Type; union { /// \brief When Kind == SK_ResolvedOverloadedFunction or Kind == /// SK_UserConversion, the function that the expression should be /// resolved to or the conversion function to call, respectively. /// When Kind == SK_ConstructorInitialization or SK_ListConstruction, /// the constructor to be called. /// /// Always a FunctionDecl, plus a Boolean flag telling if it was /// selected from an overloaded set having size greater than 1. /// For conversion decls, the naming class is the source type. /// For construct decls, the naming class is the target type. struct { bool HadMultipleCandidates; FunctionDecl *Function; DeclAccessPair FoundDecl; } Function; /// \brief When Kind = SK_ConversionSequence, the implicit conversion /// sequence. ImplicitConversionSequence *ICS; /// \brief When Kind = SK_RewrapInitList, the syntactic form of the /// wrapping list. InitListExpr *WrappingSyntacticList; }; void Destroy(); }; private: /// \brief The kind of initialization sequence computed. enum SequenceKind SequenceKind; /// \brief Steps taken by this initialization. SmallVector Steps; public: /// \brief Describes why initialization failed. enum FailureKind { /// \brief Too many initializers provided for a reference. FK_TooManyInitsForReference, /// \brief Array must be initialized with an initializer list. FK_ArrayNeedsInitList, /// \brief Array must be initialized with an initializer list or a /// string literal. FK_ArrayNeedsInitListOrStringLiteral, /// \brief Array type mismatch. FK_ArrayTypeMismatch, /// \brief Non-constant array initializer FK_NonConstantArrayInit, /// \brief Cannot resolve the address of an overloaded function. FK_AddressOfOverloadFailed, /// \brief Overloading due to reference initialization failed. FK_ReferenceInitOverloadFailed, /// \brief Non-const lvalue reference binding to a temporary. FK_NonConstLValueReferenceBindingToTemporary, /// \brief Non-const lvalue reference binding to an lvalue of unrelated /// type. FK_NonConstLValueReferenceBindingToUnrelated, /// \brief Rvalue reference binding to an lvalue. FK_RValueReferenceBindingToLValue, /// \brief Reference binding drops qualifiers. FK_ReferenceInitDropsQualifiers, /// \brief Reference binding failed. FK_ReferenceInitFailed, /// \brief Implicit conversion failed. FK_ConversionFailed, /// \brief Implicit conversion failed. FK_ConversionFromPropertyFailed, /// \brief Too many initializers for scalar FK_TooManyInitsForScalar, /// \brief Reference initialization from an initializer list FK_ReferenceBindingToInitList, /// \brief Initialization of some unused destination type with an /// initializer list. FK_InitListBadDestinationType, /// \brief Overloading for a user-defined conversion failed. FK_UserConversionOverloadFailed, /// \brief Overloading for initialization by constructor failed. FK_ConstructorOverloadFailed, /// \brief Overloading for list-initialization by constructor failed. FK_ListConstructorOverloadFailed, /// \brief Default-initialization of a 'const' object. FK_DefaultInitOfConst, /// \brief Initialization of an incomplete type. FK_Incomplete, /// \brief Variable-length array must not have an initializer. FK_VariableLengthArrayHasInitializer, /// \brief List initialization failed at some point. FK_ListInitializationFailed, /// \brief Initializer has a placeholder type which cannot be /// resolved by initialization. FK_PlaceholderType, /// \brief Failed to initialize a std::initializer_list because copy /// construction of some element failed. FK_InitListElementCopyFailure, /// \brief List-copy-initialization chose an explicit constructor. FK_ExplicitConstructor }; private: /// \brief The reason why initialization failed. FailureKind Failure; /// \brief The failed result of overload resolution. OverloadingResult FailedOverloadResult; /// \brief The candidate set created when initialization failed. OverloadCandidateSet FailedCandidateSet; /// \brief The incomplete type that caused a failure. QualType FailedIncompleteType; /// \brief Prints a follow-up note that highlights the location of /// the initialized entity, if it's remote. void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity); public: /// \brief Try to perform initialization of the given entity, creating a /// record of the steps required to perform the initialization. /// /// The generated initialization sequence will either contain enough /// information to diagnose /// /// \param S the semantic analysis object. /// /// \param Entity the entity being initialized. /// /// \param Kind the kind of initialization being performed. /// /// \param Args the argument(s) provided for initialization. /// /// \param NumArgs the number of arguments provided for initialization. InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr **Args, unsigned NumArgs); ~InitializationSequence(); /// \brief Perform the actual initialization of the given entity based on /// the computed initialization sequence. /// /// \param S the semantic analysis object. /// /// \param Entity the entity being initialized. /// /// \param Kind the kind of initialization being performed. /// /// \param Args the argument(s) provided for initialization, ownership of /// which is transferred into the routine. /// /// \param ResultType if non-NULL, will be set to the type of the /// initialized object, which is the type of the declaration in most /// cases. However, when the initialized object is a variable of /// incomplete array type and the initializer is an initializer /// list, this type will be set to the completed array type. /// /// \returns an expression that performs the actual object initialization, if /// the initialization is well-formed. Otherwise, emits diagnostics /// and returns an invalid expression. ExprResult Perform(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Args, QualType *ResultType = 0); /// \brief Diagnose an potentially-invalid initialization sequence. /// /// \returns true if the initialization sequence was ill-formed, /// false otherwise. bool Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr **Args, unsigned NumArgs); /// \brief Determine the kind of initialization sequence computed. enum SequenceKind getKind() const { return SequenceKind; } /// \brief Set the kind of sequence computed. void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; } /// \brief Determine whether the initialization sequence is valid. operator bool() const { return !Failed(); } /// \brief Determine whether the initialization sequence is invalid. bool Failed() const { return SequenceKind == FailedSequence; } typedef SmallVector::const_iterator step_iterator; step_iterator step_begin() const { return Steps.begin(); } step_iterator step_end() const { return Steps.end(); } /// \brief Determine whether this initialization is a direct reference /// binding (C++ [dcl.init.ref]). bool isDirectReferenceBinding() const; /// \brief Determine whether this initialization failed due to an ambiguity. bool isAmbiguous() const; /// \brief Determine whether this initialization is direct call to a /// constructor. bool isConstructorInitialization() const; /// \brief Returns whether the last step in this initialization sequence is a /// narrowing conversion, defined by C++0x [dcl.init.list]p7. /// /// If this function returns true, *isInitializerConstant will be set to /// describe whether *Initializer was a constant expression. If /// *isInitializerConstant is set to true, *ConstantValue will be set to the /// evaluated value of *Initializer. bool endsWithNarrowing(ASTContext &Ctx, const Expr *Initializer, bool *isInitializerConstant, APValue *ConstantValue) const; /// \brief Add a new step in the initialization that resolves the address /// of an overloaded function to a specific function declaration. /// /// \param Function the function to which the overloaded function reference /// resolves. void AddAddressOverloadResolutionStep(FunctionDecl *Function, DeclAccessPair Found, bool HadMultipleCandidates); /// \brief Add a new step in the initialization that performs a derived-to- /// base cast. /// /// \param BaseType the base type to which we will be casting. /// /// \param IsLValue true if the result of this cast will be treated as /// an lvalue. void AddDerivedToBaseCastStep(QualType BaseType, ExprValueKind Category); /// \brief Add a new step binding a reference to an object. /// /// \param BindingTemporary True if we are binding a reference to a temporary /// object (thereby extending its lifetime); false if we are binding to an /// lvalue or an lvalue treated as an rvalue. /// /// \param UnnecessaryCopy True if we should check for a copy /// constructor for a completely unnecessary but void AddReferenceBindingStep(QualType T, bool BindingTemporary); /// \brief Add a new step that makes an extraneous copy of the input /// to a temporary of the same class type. /// /// This extraneous copy only occurs during reference binding in /// C++98/03, where we are permitted (but not required) to introduce /// an extra copy. At a bare minimum, we must check that we could /// call the copy constructor, and produce a diagnostic if the copy /// constructor is inaccessible or no copy constructor matches. // /// \param T The type of the temporary being created. void AddExtraneousCopyToTemporary(QualType T); /// \brief Add a new step invoking a conversion function, which is either /// a constructor or a conversion function. void AddUserConversionStep(FunctionDecl *Function, DeclAccessPair FoundDecl, QualType T, bool HadMultipleCandidates); /// \brief Add a new step that performs a qualification conversion to the /// given type. void AddQualificationConversionStep(QualType Ty, ExprValueKind Category); /// \brief Add a new step that applies an implicit conversion sequence. void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, QualType T); /// \brief Add a list-initialization step. void AddListInitializationStep(QualType T); /// \brief Add a constructor-initialization step. /// /// \arg FromInitList The constructor call is syntactically an initializer /// list. /// \arg AsInitList The constructor is called as an init list constructor. void AddConstructorInitializationStep(CXXConstructorDecl *Constructor, AccessSpecifier Access, QualType T, bool HadMultipleCandidates, bool FromInitList, bool AsInitList); /// \brief Add a zero-initialization step. void AddZeroInitializationStep(QualType T); /// \brief Add a C assignment step. // // FIXME: It isn't clear whether this should ever be needed; // ideally, we would handle everything needed in C in the common // path. However, that isn't the case yet. void AddCAssignmentStep(QualType T); /// \brief Add a string init step. void AddStringInitStep(QualType T); /// \brief Add an Objective-C object conversion step, which is /// always a no-op. void AddObjCObjectConversionStep(QualType T); /// \brief Add an array initialization step. void AddArrayInitStep(QualType T); /// \brief Add a parenthesized array initialization step. void AddParenthesizedArrayInitStep(QualType T); /// \brief Add a step to pass an object by indirect copy-restore. void AddPassByIndirectCopyRestoreStep(QualType T, bool shouldCopy); /// \brief Add a step to "produce" an Objective-C object (by /// retaining it). void AddProduceObjCObjectStep(QualType T); /// \brief Add a step to construct a std::initializer_list object from an /// initializer list. void AddStdInitializerListConstructionStep(QualType T); /// \brief Add steps to unwrap a initializer list for a reference around a /// single element and rewrap it at the end. void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic); /// \brief Note that this initialization sequence failed. void SetFailed(FailureKind Failure) { SequenceKind = FailedSequence; this->Failure = Failure; assert((Failure != FK_Incomplete || !FailedIncompleteType.isNull()) && "Incomplete type failure requires a type!"); } /// \brief Note that this initialization sequence failed due to failed /// overload resolution. void SetOverloadFailure(FailureKind Failure, OverloadingResult Result); /// \brief Retrieve a reference to the candidate set when overload /// resolution fails. OverloadCandidateSet &getFailedCandidateSet() { return FailedCandidateSet; } /// \brief Get the overloading result, for when the initialization /// sequence failed due to a bad overload. OverloadingResult getFailedOverloadResult() const { return FailedOverloadResult; } /// \brief Note that this initialization sequence failed due to an /// incomplete type. void setIncompleteTypeFailure(QualType IncompleteType) { FailedIncompleteType = IncompleteType; SetFailed(FK_Incomplete); } /// \brief Determine why initialization failed. FailureKind getFailureKind() const { assert(Failed() && "Not an initialization failure!"); return Failure; } /// \brief Dump a representation of this initialization sequence to /// the given stream, for debugging purposes. void dump(raw_ostream &OS) const; /// \brief Dump a representation of this initialization sequence to /// standard error, for debugging purposes. void dump() const; }; } // end namespace clang #endif // LLVM_CLANG_SEMA_INITIALIZATION_H Index: vendor/clang/dist/include/clang/Sema/Sema.h =================================================================== --- vendor/clang/dist/include/clang/Sema/Sema.h (revision 235808) +++ vendor/clang/dist/include/clang/Sema/Sema.h (revision 235809) @@ -1,6891 +1,6879 @@ //===--- 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/Sema/Ownership.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/LocInfoType.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/NSAPI.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" #include "clang/Basic/ExpressionTraits.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include #include namespace llvm { class APSInt; template struct DenseMapInfo; template class DenseSet; class SmallBitVector; } namespace clang { class ADLResult; class ASTConsumer; class ASTContext; class ASTMutationListener; class ASTReader; class ASTWriter; class ArrayType; class AttributeList; class BlockDecl; class CXXBasePath; class CXXBasePaths; class CXXBindTemporaryExpr; typedef SmallVector CXXCastPath; class CXXConstructorDecl; class CXXConversionDecl; class CXXDestructorDecl; class CXXFieldCollector; class CXXMemberCallExpr; class CXXMethodDecl; class CXXScopeSpec; class CXXTemporary; class CXXTryStmt; class CallExpr; class ClassTemplateDecl; class ClassTemplatePartialSpecializationDecl; class ClassTemplateSpecializationDecl; class CodeCompleteConsumer; class CodeCompletionAllocator; class CodeCompletionTUInfo; class CodeCompletionResult; class Decl; class DeclAccessPair; class DeclContext; class DeclRefExpr; class DeclaratorDecl; class DeducedTemplateArgument; class DependentDiagnostic; class DesignatedInitExpr; class Designation; class EnumConstantDecl; class Expr; class ExtVectorType; class ExternalSemaSource; class FormatAttr; class FriendDecl; class FunctionDecl; class FunctionProtoType; class FunctionTemplateDecl; class ImplicitConversionSequence; class InitListExpr; class InitializationKind; class InitializationSequence; class InitializedEntity; class IntegerLiteral; class LabelStmt; class LambdaExpr; class LangOptions; class LocalInstantiationScope; class LookupResult; class MacroInfo; class MultiLevelTemplateArgumentList; class NamedDecl; class NonNullAttr; 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 OverloadCandidateSet; class OverloadExpr; class ParenListExpr; class ParmVarDecl; class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; class StandardConversionSequence; class Stmt; class StringLiteral; class SwitchStmt; class TargetAttributesSema; 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 UnqualifiedId; class UnresolvedLookupExpr; class UnresolvedMemberExpr; class UnresolvedSetImpl; class UnresolvedSetIterator; class UsingDecl; class UsingShadowDecl; class ValueDecl; class VarDecl; class VisibilityAttr; class VisibleDeclConsumer; class IndirectFieldDecl; namespace sema { class AccessedEntity; class BlockScopeInfo; class CompoundScopeInfo; class DelayedDiagnostic; class FunctionScopeInfo; class LambdaScopeInfo; class PossiblyUnreachableDiag; class TemplateDeductionInfo; } // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. typedef std::pair, SourceLocation> UnexpandedParameterPack; /// Sema - This implements semantic analysis and AST building for C. class Sema { Sema(const Sema&); // DO NOT IMPLEMENT void operator=(const Sema&); // DO NOT IMPLEMENT mutable const TargetAttributesSema* TheTargetAttributesSema; 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 Source of additional semantic information. ExternalSemaSource *ExternalSource; /// \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; /// PackContext - Manages the stack for #pragma pack. An alignment /// of 0 indicates default alignment. void *PackContext; // Really a "PragmaPackStack*" bool MSStructPragmaOn; // True when #pragma ms_struct on /// VisContext - Manages the stack for #pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" /// ExprNeedsCleanups - True if the current evaluation context /// requires cleanups to be run at its conclusion. bool ExprNeedsCleanups; /// 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; 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; /// \brief The set of types for which we have already complained about the /// definitions being hidden. /// /// This set is used to suppress redundant diagnostics. llvm::SmallPtrSet HiddenDefinitions; /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. OwningPtr FieldCollector; 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. OwningPtr PureVirtualClassDiagSet; /// ParsingInitForAutoVars - a set of declarations with auto types for which /// we are currently parsing the initializer. llvm::SmallPtrSet ParsingInitForAutoVars; /// \brief A mapping from external names to the most recent /// locally-scoped external declaration with that name. /// /// This map contains external declarations introduced in local /// scoped, e.g., /// /// \code /// void f() { /// void foo(int, int); /// } /// \endcode /// /// Here, the name "foo" will be associated with the declaration on /// "foo" within f. This name is not visible outside of /// "f". However, we still find it in two cases: /// /// - If we are declaring another external with the name "foo", we /// can find "foo" as a previous declaration, so that the types /// of this external declaration can be checked for /// compatibility. /// /// - If we would implicitly declare "foo" (e.g., due to a call to /// "foo" in C when no prototype or definition is visible), then /// we find this declaration of "foo" and complain that it is /// not visible. llvm::DenseMap LocallyScopedExternalDecls; /// \brief Look for a locally scoped external declaration by the given name. llvm::DenseMap::iterator findLocallyScopedExternalDecl(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 destructors seen during a class definition that had their + /// exception spec computation delayed because it depended on an unparsed + /// exception spec. + SmallVector DelayedDestructorExceptionSpecs; + /// \brief All the overriding destructors seen during a class definition /// (there could be multiple due to nested classes) that had their exception /// spec checks delayed, plus the overridden destructor. SmallVector, 2> DelayedDestructorExceptionSpecChecks; /// \brief Callback to the parser to parse templated functions when needed. typedef void LateTemplateParserCB(void *P, const FunctionDecl *FD); LateTemplateParserCB *LateTemplateParser; void *OpaqueParser; void SetLateTemplateParser(LateTemplateParserCB *LTP, void *P) { LateTemplateParser = LTP; OpaqueParser = P; } class DelayedDiagnostics; class ParsingDeclState { unsigned SavedStackSize; friend class Sema::DelayedDiagnostics; }; class ProcessingContextState { unsigned SavedParsingDepth; unsigned SavedActiveStackBase; friend class Sema::DelayedDiagnostics; }; /// A class which encapsulates the logic for delaying diagnostics /// during parsing and other processing. class DelayedDiagnostics { /// \brief The stack of diagnostics that were delayed due to being /// produced during the parsing of a declaration. sema::DelayedDiagnostic *Stack; /// \brief The number of objects on the delayed-diagnostics stack. unsigned StackSize; /// \brief The current capacity of the delayed-diagnostics stack. unsigned StackCapacity; /// \brief The index of the first "active" delayed diagnostic in /// the stack. When parsing class definitions, we ignore active /// delayed diagnostics from the surrounding context. unsigned ActiveStackBase; /// \brief The depth of the declarations we're currently parsing. /// This gets saved and reset whenever we enter a class definition. unsigned ParsingDepth; public: DelayedDiagnostics() : Stack(0), StackSize(0), StackCapacity(0), ActiveStackBase(0), ParsingDepth(0) {} ~DelayedDiagnostics() { delete[] reinterpret_cast(Stack); } /// Adds a delayed diagnostic. void add(const sema::DelayedDiagnostic &diag); /// Determines whether diagnostics should be delayed. bool shouldDelayDiagnostics() { return ParsingDepth > 0; } /// Observe that we've started parsing a declaration. Access and /// deprecation diagnostics will be delayed; when the declaration /// is completed, all active delayed diagnostics will be evaluated /// in its context, and then active diagnostics stack will be /// popped down to the saved depth. ParsingDeclState pushParsingDecl() { ParsingDepth++; ParsingDeclState state; state.SavedStackSize = StackSize; return state; } /// Observe that we're completed parsing a declaration. static void popParsingDecl(Sema &S, ParsingDeclState state, Decl *decl); /// Observe that we've started processing a different context, the /// contents of which are semantically separate from the /// declarations it may lexically appear in. This sets aside the /// current stack of active diagnostics and starts afresh. ProcessingContextState pushContext() { assert(StackSize >= ActiveStackBase); ProcessingContextState state; state.SavedParsingDepth = ParsingDepth; state.SavedActiveStackBase = ActiveStackBase; ActiveStackBase = StackSize; ParsingDepth = 0; return state; } /// Observe that we've stopped processing a context. This /// restores the previous stack of active diagnostics. void popContext(ProcessingContextState state) { assert(ActiveStackBase == StackSize); assert(ParsingDepth == 0); ActiveStackBase = state.SavedActiveStackBase; ParsingDepth = state.SavedParsingDepth; } } 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) : S(S), SavedContext(S.CurContext), SavedContextState(S.DelayedDiagnostics.pushContext()), SavedCXXThisTypeOverride(S.CXXThisTypeOverride) { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; } void pop() { if (!SavedContext) return; S.CurContext = SavedContext; S.DelayedDiagnostics.popContext(SavedContextState); S.CXXThisTypeOverride = SavedCXXThisTypeOverride; SavedContext = 0; } ~ContextRAII() { pop(); } }; /// WeakUndeclaredIdentifiers - Identifiers contained in /// #pragma weak before declared. rare. may alias another /// identifier, declared or undeclared llvm::DenseMap 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::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. llvm::OwningPtr NSAPIObj; /// \brief The declaration of the Objective-C NSNumber class. ObjCInterfaceDecl *NSNumberDecl; /// \brief The Objective-C NSNumber methods used to create NSNumber literals. ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; /// \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; /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; /// A flag that is set when parsing a -dealloc method and no [super dealloc] /// call was found yet. bool ObjCShouldCallSuperDealloc; /// A flag that is set when parsing a -finalize method and no [super finalize] /// call was found yet. bool ObjCShouldCallSuperFinalize; /// \brief Describes how the expressions currently being parsed are /// evaluated at run-time, if at all. enum 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 context is "potentially evaluated" in C++11 terms, /// but the expression is evaluated at compile-time (like the values of /// cases in a switch statment). 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. bool ParentNeedsCleanups; /// \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; llvm::SmallPtrSet SavedMaybeODRUseExprs; /// \brief The lambdas that are present within this context, if it /// is indeed an unevaluated context. llvm::SmallVector Lambdas; /// \brief The declaration that provides context for the lambda expression /// if the normal declaration context does not suffice, e.g., in a /// default function argument. Decl *LambdaContextDecl; /// \brief The context information used to mangle lambda expressions /// within this context. /// /// This mangling information is allocated lazily, since most contexts /// do not have lambda expressions. LambdaMangleContext *LambdaMangle; /// \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. llvm::SmallVector DelayedDecltypeCalls; /// \brief If we are processing a decltype type, a set of temporary binding /// expressions for which we have deferred checking the destructor. llvm::SmallVector DelayedDecltypeBinds; ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, bool ParentNeedsCleanups, Decl *LambdaContextDecl, bool IsDecltype) : Context(Context), ParentNeedsCleanups(ParentNeedsCleanups), IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), LambdaContextDecl(LambdaContextDecl), LambdaMangle() { } ~ExpressionEvaluationContextRecord() { delete LambdaMangle; } /// \brief Retrieve the mangling context for lambdas. LambdaMangleContext &getLambdaMangleContext() { assert(LambdaContextDecl && "Need to have a lambda context declaration"); if (!LambdaMangle) LambdaMangle = new LambdaMangleContext; return *LambdaMangle; } }; /// A stack of expression evaluation contexts. SmallVector ExprEvalContexts; /// SpecialMemberOverloadResult - The overloading result for a special member /// function. /// - /// This is basically a wrapper around PointerIntPair. The lowest bit of the - /// integer is used to determine whether we have a parameter qualification - /// match, the second-lowest is whether we had success in resolving the - /// overload to a unique non-deleted function. - /// - /// The ConstParamMatch bit represents whether, when looking up a copy - /// constructor or assignment operator, we found a potential copy - /// constructor/assignment operator whose first parameter is const-qualified. - /// This is used for determining parameter types of other objects and is - /// utterly meaningless on other types of special members. + /// This is basically a wrapper around PointerIntPair. The lowest bits of the + /// integer are used to determine whether overload resolution succeeded, and + /// whether, when looking up a copy constructor or assignment operator, we + /// found a potential copy constructor/assignment operator whose first + /// parameter is const-qualified. This is used for determining parameter types + /// of other objects and is utterly meaningless on other types of special + /// members. class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode { public: enum Kind { NoMemberOrDeleted, Ambiguous, - SuccessNonConst, - SuccessConst + Success }; private: llvm::PointerIntPair Pair; public: SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID) : FastFoldingSetNode(ID) {} 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); } - - bool hasSuccess() const { return getKind() >= SuccessNonConst; } - bool hasConstParamMatch() const { return getKind() == SuccessConst; } }; /// \brief A cache of special member function overload resolution results /// for C++ records. llvm::FoldingSet SpecialMemberCache; /// \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 with /// internal linkage in this translation unit. llvm::DenseMap UndefinedInternals; 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"). GlobalMethodPool MethodPool; /// Method selectors used in a @selector expression. Used for implementation /// of -Wselector. llvm::DenseMap ReferencedSelectors; void ReadMethodPool(Selector Sel); /// Private Helper predicate to check for 'self'. bool isSelfExpr(Expr *RExpr); /// \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); public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind = TU_Complete, CodeCompleteConsumer *CompletionConsumer = 0); ~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; } const TargetAttributesSema &getTargetAttributesSema() const; Preprocessor &getPreprocessor() const { return PP; } ASTContext &getASTContext() const { return Context; } ASTConsumer &getASTConsumer() const { return Consumer; } ASTMutationListener *getASTMutationListener() const; 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) { } ~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); } }; /// \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. const char *getFixItZeroInitializerForType(QualType T) const; ExprResult Owned(Expr* E) { return E; } ExprResult Owned(ExprResult R) { return R; } StmtResult Owned(Stmt* S) { return S; } void ActOnEndOfTranslationUnit(); void CheckDelegatingCtorCycles(); Scope *getScopeForContext(DeclContext *Ctx); void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator); void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0, const Decl *D = 0, const BlockExpr *blkExpr = 0); sema::FunctionScopeInfo *getCurFunction() const { return FunctionScopes.back(); } void PushCompoundScope(); void PopCompoundScope(); sema::CompoundScopeInfo &getCurCompoundScope() const; bool hasAnyUnrecoverableErrorsInThisFunction() const; /// \brief Retrieve the current block, if any. sema::BlockScopeInfo *getCurBlock(); /// \brief Retrieve the current lambda expression, if any. sema::LambdaScopeInfo *getCurLambda(); /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls SmallVector &WeakTopLevelDecls() { return WeakTopLevelDecl; } //===--------------------------------------------------------------------===// // Type Analysis / Processing: SemaType.cpp. // QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs); QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVR) { return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR)); } 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); QualType BuildFunctionType(QualType T, QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, bool HasTrailingReturn, unsigned Quals, RefQualifierKind RefQualifier, SourceLocation Loc, DeclarationName Entity, FunctionType::ExtInfo Info); 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); 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 = 0); CanThrowResult canThrow(const Expr *E); const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT); bool CheckSpecifiedExceptionType(QualType T, const 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 *MissingExceptionSpecification = 0, bool *MissingEmptyExceptionSpecification = 0, bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false); bool CheckExceptionSpecSubset( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Superset, SourceLocation SuperLoc, const FunctionProtoType *Subset, SourceLocation SubLoc); bool CheckParamExceptionSpec(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); bool RequireCompleteType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD, std::pair Note); bool RequireCompleteType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD); bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID); bool RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD, std::pair Note); bool RequireLiteralType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD); QualType getElaboratedType(ElaboratedTypeKeyword Keyword, const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); QualType BuildDecltypeType(Expr *E, SourceLocation Loc); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // /// List of decls defined in a function prototype. This contains EnumConstants /// that incorrectly end up in translation unit scope because there is no /// function to pin them on. ActOnFunctionDeclarator reads this list and patches /// them into the FunctionDecl. std::vector DeclsInPrototypeScope; /// Nonzero if we are currently parsing a function declarator. This is a counter /// as opposed to a boolean so we can deal with nested function declarators /// such as: /// void f(void (*g)(), ...) unsigned InFunctionDeclarator; DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = 0); void DiagnoseUseOfUnimplementedSelectors(); ParsedType getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS = 0, bool isClassName = false, bool HasTrailingDot = false, ParsedType ObjectType = ParsedType(), bool IsCtorOrDtorName = false, bool WantNontrivialTypeSourceInfo = false, IdentifierInfo **CorrectedII = 0); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); bool DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType); /// \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_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 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); return Template; } TemplateNameKind getTemplateNameKind() const { assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate); return Kind == NC_TypeTemplate? TNK_Type_template : TNK_Function_template; } }; /// \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. NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken); Decl *ActOnDeclarator(Scope *S, Declarator &D); Decl *HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists); void RegisterLocallyScopedExternCDecl(NamedDecl *ND, const LookupResult &Previous, Scope *S); bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, SourceLocation Loc); void DiagnoseFunctionSpecifiers(Declarator& D); void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); void CheckShadow(Scope *S, VarDecl *D); void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); 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); // Returns true if the variable declaration is a redeclaration bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); void CheckCompleteVariableDeclaration(VarDecl *var); void ActOnStartFunctionDeclarator(); void ActOnEndFunctionDeclarator(); 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(CXXRecordDecl *DC, CXXMethodDecl *MD); // Returns true if the function declaration is a redeclaration bool CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization); void CheckMain(FunctionDecl *FD, const DeclSpec &D); 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, StorageClass SCAsWritten); void ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, Expr *defarg); void ActOnParamUnparsedDefaultArgument(Decl *param, SourceLocation EqualLoc, SourceLocation ArgLoc); void ActOnParamDefaultArgumentError(Decl *param); bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, SourceLocation EqualLoc); void CheckSelfReference(Decl *OrigDecl, Expr *E); void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit, bool TypeMayContainAuto); void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto); void ActOnInitializerError(Decl *Dcl); void ActOnCXXForRangeDecl(Decl *D); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); void FinalizeDeclaration(Decl *D); DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, Decl **Group, unsigned NumDecls); DeclGroupPtrTy BuildDeclaratorGroup(Decl **Group, unsigned NumDecls, bool TypeMayContainAuto = true); void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls); void CheckForFunctionRedefinition(FunctionDecl *FD); Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D); Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D); void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); /// 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(ParmVarDecl * const *Begin, ParmVarDecl * const *End); /// \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(ParmVarDecl * const *Begin, ParmVarDecl * const *End, QualType ReturnTy, NamedDecl *D); void DiagnoseInvalidJumps(Stmt *Body); Decl *ActOnFileScopeAsmDecl(Expr *expr, SourceLocation AsmLoc, SourceLocation RParenLoc); /// \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 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); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, MultiTemplateParamsArg TemplateParams); Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, AccessSpecifier AS, RecordDecl *Record); Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record); 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); 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, bool HasInit, AccessSpecifier AS); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitfieldWidth, bool HasInit, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D = 0); enum CXXSpecialMember { CXXDefaultConstructor, CXXCopyConstructor, CXXMoveConstructor, CXXCopyAssignment, CXXMoveAssignment, CXXDestructor, CXXInvalid }; bool CheckNontrivialField(FieldDecl *FD); void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem); 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, llvm::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); 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, 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, SourceLocation RBraceLoc); 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, const EnumDecl *Prev); Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, AttributeList *Attrs, SourceLocation EqualLoc, Expr *Val); void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, Decl *EnumDecl, Decl **Elements, unsigned NumElements, 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 ExplicitInstantiationOrSpecialization When true, we are checking /// whether the declaration is in scope for the purposes of explicit template /// instantiation or specialization. The default is false. bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0, bool ExplicitInstantiationOrSpecialization = 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); void mergeDeclAttributes(Decl *New, Decl *Old, bool MergeDeprecation = true); void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, Decl *Old, Scope *S); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, Scope *S); void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old); void MergeVarDecl(VarDecl *New, LookupResult &OldDecls); void MergeVarDeclTypes(VarDecl *New, VarDecl *Old); void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); 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 }; /// 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); /// \brief Checks availability of the function depending on the current /// function context.Inside an unavailable function,unavailability is ignored. /// /// \returns true if \arg 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 FunctionArgTypesAreEqual(const FunctionProtoType *OldType, const FunctionProtoType *NewType, unsigned *ArgPos = 0); void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, QualType FromType, QualType ToType); CastKind PrepareCastToObjCObjectPointer(ExprResult &E); bool CheckPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath& BasePath, bool IgnoreBaseAccess); 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 IsNoReturnConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); 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. }; ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, llvm::APSInt &Value, CCEKind CCE); ExprResult ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *FromE, const PartialDiagnostic &NotIntDiag, const PartialDiagnostic &IncompleteDiag, const PartialDiagnostic &ExplicitConvDiag, const PartialDiagnostic &ExplicitConvNote, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &AmbigNote, const PartialDiagnostic &ConvDiag, bool AllowScopedEnumerations); enum ObjCSubscriptKind { OS_Array, OS_Dictionary, OS_Error }; ObjCSubscriptKind CheckSubscriptingKind(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::SmallPtrSet AssociatedNamespaceSet; typedef llvm::SmallPtrSet AssociatedClassSet; void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl, llvm::ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, bool AllowExplicit = false); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, llvm::ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, TemplateArgumentListInfo *ExplicitTemplateArgs = 0); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, llvm::ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, Expr::Classification ObjectClassification, llvm::ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, llvm::ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); void AddConversionCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet); void AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, Expr *Object, llvm::ArrayRef Args, OverloadCandidateSet& CandidateSet); void AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, SourceRange OpRange = SourceRange()); void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator = false, unsigned NumContextualBoolArguments = 0); void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, bool Operator, SourceLocation Loc, llvm::ArrayRef Args, TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false, bool StdNamespaceIsAssociated = false); // Emit as a 'note' the specific overload candidate void NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType = QualType()); // Emit as a series of 'note's all template and non-templates // identified by the expression Expr void NoteAllOverloadCandidates(Expr* E, QualType DestType = QualType()); // [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 = 0); FunctionDecl *ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, bool Complain = false, DeclAccessPair* Found = 0); bool ResolveAndFixSingleFunctionTemplateSpecialization( ExprResult &SrcExpr, bool DoFunctionPointerConverion = false, bool Complain = false, const 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, llvm::ArrayRef Args, OverloadCandidateSet &CandidateSet, bool PartialOverloading = false); ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, Expr *ExecConfig, bool AllowTypoCorrection=true); ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned Opc, const UnresolvedSetImpl &Fns, Expr *input); ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, unsigned 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, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc); ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc); ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc); /// 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(ParmVarDecl **Param, ParmVarDecl **ParamEnd, 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 the name of an Objective-C protocol. LookupObjCProtocolName, /// Look up implicit 'self' parameter of an objective-c method. LookupObjCImplicitSelfParam, /// \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 }; SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis); private: bool CppLookupName(LookupResult &R, Scope *S); // \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::DenseMap KnownNamespaces; /// \brief Whether we have already loaded known namespaces from an extenal /// source. bool LoadedExternalKnownNamespaces; public: /// \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 LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl = NotForRedeclaration); 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, - bool *ConstParam = 0); + unsigned Quals); CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, - bool RValueThis, unsigned ThisQuals, - bool *ConstParam = 0); + bool RValueThis, unsigned ThisQuals); CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class); CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, bool RValueThis, unsigned ThisQuals); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef ArgTys, bool AllowRawAndTemplate); void ArgumentDependentLookup(DeclarationName Name, bool Operator, SourceLocation Loc, llvm::ArrayRef Args, ADLResult &Functions, bool StdNamespaceIsAssociated = false); void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true); void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true); TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, DeclContext *MemberContext = 0, bool EnteringContext = false, const ObjCObjectPointerType *OPT = 0); void FindAssociatedClassesAndNamespaces(llvm::ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses); void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool ExplicitInstantiationOrSpecialization); bool 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. // Decl attributes - this routine is the top level dispatcher. void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, bool NonInheritable = true, bool Inheritable = true); void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, bool NonInheritable = true, bool Inheritable = true); bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, const AttributeList *AttrList); void checkUnusedDeclAttributes(Declarator &D); bool CheckRegparmAttr(const AttributeList &attr, unsigned &value); bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC); bool CheckNoReturnAttr(const AttributeList &attr); /// \brief Stmt attributes - this routine is the top level dispatcher. StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs, SourceRange Range); void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, bool &IncompleteImpl, unsigned DiagID); 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); bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl, ObjCInterfaceDecl *IDecl); typedef llvm::DenseSet > SelectorSet; typedef llvm::DenseMap ProtocolsMethodsMap; /// CheckProtocolMethodDefs - This routine checks unimplemented /// methods declared in protocol, and those referenced by it. /// \param IDecl - Used for checking for methods which may have been /// inherited. void CheckProtocolMethodDefs(SourceLocation ImpLoc, ObjCProtocolDecl *PDecl, bool& IncompleteImpl, const SelectorSet &InsMap, const SelectorSet &ClsMap, ObjCContainerDecl *CDecl); /// 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, const SelectorSet &InsMap); /// DefaultSynthesizeProperties - This routine default synthesizes all /// properties which must be synthesized in class's @implementation. void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, ObjCInterfaceDecl *IDecl); void DefaultSynthesizeProperties(Scope *S, Decl *D); /// CollectImmediateProperties - This routine collects all properties in /// the class and its conforming protocols; but not those it its super class. void CollectImmediateProperties(ObjCContainerDecl *CDecl, llvm::DenseMap& PropMap, llvm::DenseMap& SuperPropMap); /// LookupPropertyDecl - Looks up a property in the current class and all /// its protocols. ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl, IdentifierInfo *II); /// Called by ActOnProperty to handle @property declarations in //// class extensions. Decl *HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, const bool isAssign, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, bool *isOverridingProperty, TypeSourceInfo *T, 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, Selector SetterSel, const bool isAssign, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, TypeSourceInfo *T, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = 0); /// 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, ObjCContainerDecl* IDecl); void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D); 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 warn, bool instance); 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, bool warn=true) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, warn, /*instance*/true); } /// LookupFactoryMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass=false, bool warn=true) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, warn, /*instance*/false); } /// 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(Sema &actions) : E(0) { } // FIXME: The const_cast here is ugly. RValue references would make this // much nicer (or we could duplicate a bunch of the move semantics // emulation code from Ownership.h). FullExprArg(const FullExprArg& Other) : E(Other.E) {} ExprResult release() { return move(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 FullExprArg(ActOnFinishFullExpr(Arg).release()); } StmtResult ActOnExprStmt(FullExprArg Expr); StmtResult ActOnNullStmt(SourceLocation SemiLoc, bool HasLeadingEmptyMacro = false); void ActOnStartOfCompoundStmt(); void ActOnFinishOfCompoundStmt(); StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, MultiStmtArg 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; }; 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, const AttrVec &Attrs, Stmt *SubStmt); StmtResult ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, Decl *CondVar); StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body); StmtResult ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, Decl *CondVar, Stmt *Body); StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation CondLParen, Expr *Cond, SourceLocation CondRParen); StmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *First, FullExprArg Second, Decl *SecondVar, FullExprArg Third, SourceLocation RParenLoc, Stmt *Body); ExprResult ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection); StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, SourceLocation LParenLoc, Stmt *First, Expr *Second, SourceLocation RParenLoc, Stmt *Body); StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *LoopVar, SourceLocation ColonLoc, Expr *Collection, SourceLocation RParenLoc); StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *BeginEndDecl, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc); 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 GotoLoc, Scope *CurScope); const VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, bool AllowFunctionParameters); StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, Expr *AsmString, MultiExprArg Clobbers, SourceLocation RParenLoc, bool MSAsm = false); 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, MultiStmtArg Handlers); StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ? SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler); StmtResult ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Stmt *Block); StmtResult ActOnSEHFinallyBlock(SourceLocation Loc, Stmt *Block); 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 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); ParsingDeclState PushParsingDeclaration() { return DelayedDiagnostics.pushParsingDecl(); } void PopParsingDeclaration(ParsingDeclState state, Decl *decl) { DelayedDiagnostics::popParsingDecl(*this, state, decl); } typedef ProcessingContextState ParsingClassState; ParsingClassState PushParsingClass() { return DelayedDiagnostics.pushContext(); } void PopParsingClass(ParsingClassState state) { DelayedDiagnostics.popContext(state); } void EmitDeprecationWarning(NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass=0); void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); bool makeUnavailableInSystemHeader(SourceLocation loc, StringRef message); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. bool CanUseDecl(NamedDecl *D); bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass=0); void NoteDeletedFunction(FunctionDecl *FD); std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, Expr **Args, unsigned NumArgs); void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = 0, bool IsDecltype = false); void PopExpressionEvaluationContext(); void DiscardCleanupsInEvaluationContext(); ExprResult TranformToPotentiallyEvaluated(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. void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D); void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func); 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 refernce to the capture /// from within the current scope. Only valid when the variable can be /// captured. /// /// \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); /// \brief Try to capture the given variable. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind = TryCapture_Implicit, SourceLocation EllipsisLoc = SourceLocation()); /// \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); 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) = 0); /// \brief Figure out if an expression could be turned into a call. bool isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy, UnresolvedSetImpl &NonTemplateOverloads); /// \brief Conditionally issue a diagnostic based on the current /// evaluation context. /// /// \param stmt - If stmt 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, CorrectionCandidateCallback *CCC = 0); void DecomposeUnqualifiedId(const UnqualifiedId &Id, TemplateArgumentListInfo &Buffer, DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *&TemplateArgs); bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs = 0, llvm::ArrayRef Args = llvm::ArrayRef()); 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 = 0); ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS = 0); ExprResult BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, SourceLocation nameLoc, IndirectFieldDecl *indirectField, Expr *baseObjectExpr = 0, SourceLocation opLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, bool IsDefiniteInstance); bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen); ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo); ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL); ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D); ExprResult BuildLiteralOperatorCall(LookupResult &R, DeclarationNameInfo &SuffixInfo, ArrayRef Args, SourceLocation LitEndLoc, TemplateArgumentListInfo *ExplicitTemplateArgs = 0); ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = 0); ExprResult ActOnCharacterConstant(const Token &Tok, Scope *UDLScope = 0); 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(const Token *StringToks, unsigned NumStringToks, Scope *UDLScope = 0); ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, MultiTypeArg ArgTypes, MultiExprArg ArgExprs); ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, TypeSourceInfo **Types, Expr **Exprs, unsigned NumAssocs); // 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); 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, const 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 BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, bool SuppressQualifierCheck = false); ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); ExprResult LookupMemberExpr(LookupResult &R, ExprResult &Base, bool &IsArrow, SourceLocation OpLoc, CXXScopeSpec &SS, Decl *ObjCImpDecl, bool HasTemplateArgs); 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, bool HasTrailingLParen); void ActOnDefaultCtorInitializers(Decl *CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr **Args, unsigned NumArgs, 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 = 0, bool IsExecConfig = false); ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, Expr *Config = 0, 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); 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); /// 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, OffsetOfComponent *CompPtr, unsigned NumComponents, SourceLocation RParenLoc); ExprResult ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, ParsedType ParsedArgTy, OffsetOfComponent *CompPtr, unsigned NumComponents, 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(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); //===---------------------------- 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); void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace); NamespaceDecl *getStdNamespace() const; NamespaceDecl *getOrCreateStdNamespace(); CXXRecordDecl *getStdBadAlloc() 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 CXXConstructorDecl *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 *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, NamedDecl *Target); bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, bool isTypeName, const CXXScopeSpec &SS, SourceLocation NameLoc, const LookupResult &Previous); bool CheckUsingDeclQualifier(SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation NameLoc); NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, AttributeList *AttrList, bool IsInstantiation, bool IsTypeName, SourceLocation TypenameLoc); bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, SourceLocation TypenameLoc); Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, MultiTemplateParamsArg TemplateParams, SourceLocation UsingLoc, UnqualifiedId &Name, TypeResult Type); /// InitializeVarWithConstructor - Creates an CXXConstructExpr /// and sets it as the initializer for the the passed in VarDecl. bool InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, MultiExprArg Exprs, bool HadMultipleCandidates); /// 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, CXXConstructorDecl *Constructor, MultiExprArg Exprs, bool HadMultipleCandidates, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); /// 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++0x. // throw() comes next. // Then a throw(collected exceptions) // Finally no specification. // throw(...) is used instead if any called function uses it. // // If this exception specification cannot be known yet (for instance, // because this is the exception specification for a defaulted default // constructor and we haven't finished parsing the deferred parts of the // class yet), the C++0x standard does not specify how to behave. We // record this as an 'unknown' exception specification, which overrules // any other specification (even 'none', to keep this rule simple). 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.Context.getLangOpts().CPlusPlus0x) 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, CXXMethodDecl *Method); /// \brief Integrate an invoked expression into the collected data. void CalledExpr(Expr *E); /// \brief Specify that the exception specification can't be detemined yet. void SetDelayed() { ClearExceptions(); ComputedEST = EST_Delayed; } FunctionProtoType::ExtProtoInfo getEPI() const { FunctionProtoType::ExtProtoInfo EPI; EPI.ExceptionSpecType = getExceptionSpecType(); EPI.NumExceptions = size(); EPI.Exceptions = data(); return EPI; } }; /// \brief Determine what sort of exception specification a defaulted /// copy constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl); /// \brief Determine what sort of exception specification a defaulted /// default constructor of a class will have, and whether the parameter /// will be const. std::pair ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl); /// \brief Determine what sort of exception specification a defautled /// copy assignment operator of a class will have, and whether the /// parameter will be const. std::pair ComputeDefaultedCopyAssignmentExceptionSpecAndConst(CXXRecordDecl *ClassDecl); /// \brief Determine what sort of exception specification a defaulted move /// constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl); /// \brief Determine what sort of exception specification a defaulted move /// assignment operator of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl); /// \brief Determine what sort of exception specification a defaulted /// destructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl); /// \brief Check the given exception-specification and update the /// extended prototype information with the results. void checkExceptionSpecification(ExceptionSpecificationType EST, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr, llvm::SmallVectorImpl &Exceptions, FunctionProtoType::ExtProtoInfo &EPI); - /// \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); - /// \brief Determine if a special member function should have a deleted /// definition when it is defaulted. bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, 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); + CXXDestructorDecl *Destructor, + bool WasDelayed = false); /// \brief Declare all inherited constructors for the given class. /// /// \param ClassDecl The class declaration into which the inherited /// constructors will be added. void DeclareInheritedConstructors(CXXRecordDecl *ClassDecl); /// \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 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, ASTOwningVector &ConvertedArgs, bool AllowExplicit = false); ParsedType getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext); ParsedType getDestructorType(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); //// ActOnCXXThis - Parse 'this' pointer. ExprResult ActOnCXXThis(SourceLocation loc); /// \brief Try to retrieve the type of the 'this' pointer. /// /// \param Capture If true, capture 'this' in this context. /// /// \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. void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = 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); /// 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); ExprResult CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, bool IsThrownVarInScope); /// 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(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, Expr *ArraySize, SourceRange DirectInitRange, Expr *Initializer, bool TypeMayContainAuto = true); bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R); bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool UseGlobal, QualType AllocType, bool IsArray, Expr **PlaceArgs, unsigned NumPlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete); bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, DeclarationName Name, Expr** Args, unsigned NumArgs, DeclContext *Ctx, bool AllowMissing, FunctionDecl *&Operator, bool Diagnose = true); void DeclareGlobalNewDelete(); void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, QualType Argument, bool addMallocAttr = false); bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator, bool Diagnose = true); /// ActOnCXXDelete - Parsed a C++ 'delete' expression ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Expr *Operand); DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); ExprResult CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, bool ConvertToBoolean); ExprResult ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation LParen, Expr *Operand, SourceLocation RParen); ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen); /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support /// pseudo-functions. ExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, SourceLocation KWLoc, ParsedType Ty, SourceLocation RParen); ExprResult BuildUnaryTypeTrait(UnaryTypeTrait OTT, SourceLocation KWLoc, TypeSourceInfo *T, SourceLocation RParen); /// ActOnBinaryTypeTrait - Parsed one of the bianry type trait support /// pseudo-functions. ExprResult ActOnBinaryTypeTrait(BinaryTypeTrait OTT, SourceLocation KWLoc, ParsedType LhsTy, ParsedType RhsTy, SourceLocation RParen); ExprResult BuildBinaryTypeTrait(BinaryTypeTrait BTT, SourceLocation KWLoc, TypeSourceInfo *LhsT, TypeSourceInfo *RhsT, 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 bianry 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 DiagnoseDtorReference(SourceLocation NameLoc, Expr *MemExpr); ExprResult BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType, bool HasTrailingLParen); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName, bool HasTrailingLParen); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation TildeLoc, const DeclSpec& DS, bool HasTrailingLParen); /// 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); ExprResult ActOnFinishFullExpr(Expr *Expr); 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); bool isUnknownSpecialization(const CXXScopeSpec &SS); /// \brief The parser has parsed a global nested-name-specifier '::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \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(Scope *S, SourceLocation CCLoc, CXXScopeSpec &SS); bool isAcceptableNestedNameSpecifier(NamedDecl *SD); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation IdLoc, IdentifierInfo &II, ParsedType ObjectType); bool BuildCXXNestedNameSpecifier(Scope *S, IdentifierInfo &Identifier, SourceLocation IdentifierLoc, SourceLocation CCLoc, QualType ObjectType, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup); /// \brief The parser has parsed a nested-name-specifier 'identifier::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \param Identifier The identifier preceding the '::'. /// /// \param IdentifierLoc The location of the identifier. /// /// \param CCLoc The location of the '::'. /// /// \param ObjectType The type of the object, if we're parsing /// nested-name-specifier in a member access expression. /// /// \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). /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, IdentifierInfo &Identifier, SourceLocation IdentifierLoc, SourceLocation CCLoc, ParsedType ObjectType, bool EnteringContext, CXXScopeSpec &SS); ExprResult ActOnDecltypeExpression(Expr *E); bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, const DeclSpec &DS, SourceLocation ColonColonLoc); bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, IdentifierInfo &Identifier, SourceLocation IdentifierLoc, SourceLocation ColonLoc, ParsedType ObjectType, 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 Template, 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, bool KnownDependent = false); /// \brief Start the definition of a lambda expression. CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, llvm::ArrayRef Params, llvm::Optional ManglingNumber = llvm::Optional(), Decl *ContextDecl = 0); /// \brief Introduce the scope for a lambda expression. sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, bool ExplicitParams, bool ExplicitResultType, bool Mutable); /// \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); /// 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, bool IsInstantiation = false); /// \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, Expr **Strings, unsigned NumStrings); ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S); /// BuildObjCNumericLiteral - builds an ObjCNumericLiteral 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); ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, Expr *IndexExpr, ObjCMethodDecl *getterMethod, ObjCMethodDecl *setterMethod); ExprResult BuildObjCDictionaryLiteral(SourceRange SR, ObjCDictionaryElement *Elements, unsigned NumElements); 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); // ParseObjCProtocolExpression - Build protocol expression for @protocol ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, SourceLocation AtLoc, SourceLocation ProtoLoc, SourceLocation LParenLoc, SourceLocation RParenLoc); //===--------------------------------------------------------------------===// // C++ Declarations // Decl *ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, StringRef Lang, SourceLocation LBraceLoc); Decl *ActOnFinishLinkageSpecification(Scope *S, Decl *LinkageSpec, SourceLocation RBraceLoc); //===--------------------------------------------------------------------===// // C++ Classes // bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = 0); bool ActOnAccessSpecifier(AccessSpecifier Access, SourceLocation ASLoc, SourceLocation ColonLoc, AttributeList *Attrs = 0); Decl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, Expr *BitfieldWidth, const VirtSpecifiers &VS, bool HasDeferredInit); void ActOnCXXInClassMemberInitializer(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, Expr **Args, unsigned NumArgs, 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, CXXCtorInitializer **Initializers, unsigned NumInitializers, bool AnyErrors); 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(); typedef LazyVector DynamicClassesType; /// \brief A list of all of the dynamic classes in this translation /// unit. DynamicClassesType DynamicClasses; /// \brief Note that the vtable for the given class was used at the /// given location. void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired = false); /// 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, CXXCtorInitializer **MemInits, unsigned NumMemInits, bool AnyErrors); void CheckCompletedCXXClass(CXXRecordDecl *Record); void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList); + void ActOnFinishCXXMemberDecls(); void ActOnReenterTemplateScope(Scope *S, Decl *Template); void ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D); 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, bool Flag = true); bool IsInsideALocalClassWithinATemplateFunction(); Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *AssertMessageExpr, SourceLocation RParenLoc); FriendDecl *CheckFriendTypeDecl(SourceLocation Loc, SourceLocation FriendLoc, TypeSourceInfo *TSInfo); Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TemplateParams); Decl *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 CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record); void CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *Ctor); void CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *Ctor); void CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *Method); void CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *Ctor); void CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *Method); void CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *Dtor); //===--------------------------------------------------------------------===// // 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, bool Virtual, AccessSpecifier Access, ParsedType basetype, SourceLocation BaseLoc, SourceLocation EllipsisLoc); bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, unsigned NumBases); void ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases, unsigned NumBases); bool IsDerivedFrom(QualType Derived, QualType Base); bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths); // FIXME: I don't like this name. void BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePath); bool BasePathInvolvesVirtualBase(const CXXCastPath &BasePath); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, CXXCastPath *BasePath = 0, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, CXXCastPath *BasePath); std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); /// 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++0x override control semantics. void CheckOverrideControl(const Decl *D); /// CheckForFunctionMarkedFinal - Checks whether a virtual member function /// overrides a virtual member function marked 'final', according to /// C++0x [class.virtual]p3. 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, const InitializedEntity &Entity, AccessSpecifier Access, bool IsCopyBindingRefToTemp = false); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, const InitializedEntity &Entity, AccessSpecifier Access, const PartialDiagnostic &PDiag); AccessResult CheckDestructorAccess(SourceLocation Loc, CXXDestructorDecl *Dtor, const PartialDiagnostic &PDiag, QualType objectType = QualType()); AccessResult CheckDirectMemberAccess(SourceLocation Loc, NamedDecl *D, const PartialDiagnostic &PDiag); 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); /// A flag to suppress access checking. bool SuppressAccessChecking; /// \brief When true, access checking violations are treated as SFINAE /// failures rather than hard errors. bool AccessCheckingSFINAE; /// \brief RAII object used to temporarily suppress access checking. class SuppressAccessChecksRAII { Sema &S; bool SuppressingAccess; public: SuppressAccessChecksRAII(Sema &S, bool Suppress) : S(S), SuppressingAccess(Suppress) { if (Suppress) S.ActOnStartSuppressingAccessChecks(); } ~SuppressAccessChecksRAII() { done(); } void done() { if (!SuppressingAccess) return; S.ActOnStopSuppressingAccessChecks(); SuppressingAccess = false; } }; void ActOnStartSuppressingAccessChecks(); void ActOnStopSuppressingAccessChecks(); enum AbstractDiagSelID { AbstractNone = -1, AbstractReturnType, AbstractParamType, AbstractVariableType, AbstractFieldType, AbstractArrayType }; bool RequireNonAbstractType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD); void DiagnoseAbstractType(const CXXRecordDecl *RD); bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, AbstractDiagSelID SelID = AbstractNone); //===--------------------------------------------------------------------===// // 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); bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind); void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); Decl *ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedType DefaultArg); 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, Decl **Params, unsigned NumParams, SourceLocation RAngleLoc); /// \brief The context in which we are checking a template parameter /// list. enum TemplateParamListContext { TPC_ClassTemplate, TPC_FunctionTemplate, TPC_ClassTemplateMember, TPC_FriendFunctionTemplate, TPC_FriendFunctionTemplateDefinition, TPC_TypeAliasTemplate }; bool CheckTemplateParameterList(TemplateParameterList *NewParams, TemplateParameterList *OldParams, TemplateParamListContext TPC); TemplateParameterList * MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, bool IsFriend, bool &IsExplicitSpecialization, 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, unsigned NumOuterTemplateParamLists, TemplateParameterList **OuterTemplateParamLists); 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, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, bool IsCtorOrDtorName = false); /// \brief Parsed an elaborated-type-specifier that refers to a template-id, /// such as \c class T::template apply. /// /// \param TUK TypeResult ActOnTagTemplateIdType(TagUseKind TUK, TypeSpecifierType TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc); 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); DeclResult ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists); Decl *ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D); Decl *ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, 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); 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); /// \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, const 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 ExpansionIntoFixedList If non-NULL, will be set true to indicate /// when the template arguments contain a pack expansion that is being /// expanded into a fixed parameter list. /// /// \returns True if an error occurred, false otherwise. bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl &Converted, bool *ExpansionIntoFixedList = 0); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const 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, const TemplateArgumentLoc &Arg); 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 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 ('>'). TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, TemplateTy Template, SourceLocation TemplateNameLoc, 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]) //===--------------------------------------------------------------------===// /// \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 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. void 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 SS The nested-name-specifier that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(CXXScopeSpec &SS, 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, llvm::Optional NumExpansions); /// \brief Construct a pack expansion type from the pattern of the pack /// expansion. QualType CheckPackExpansion(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, llvm::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, llvm::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 NumUnexpanded The number of unexpanded parameter packs in /// \p Unexpanded. /// /// \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, llvm::ArrayRef Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, bool &RetainExpansion, llvm::Optional &NumExpansions); /// \brief Determine the number of arguments in the given pack expansion /// type. /// /// This routine already assumes that the pack expansion type can be /// expanded and that the number of arguments in the expansion is /// consistent across all of the unexpanded parameter packs in its pattern. unsigned 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); //===--------------------------------------------------------------------===// // C++ Template Argument Deduction (C++ [temp.deduct]) //===--------------------------------------------------------------------===// /// \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 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 Substitution of the deduced template argument values /// into a non-deduced context produced a type or value that /// produces a type that does not match the original template /// arguments provided. 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 The arguments included an overloaded function name that could /// not be resolved to a suitable function. TDK_FailedOverloadResolution }; TemplateDeductionResult DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *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, unsigned ArgIdx, QualType OriginalArgType) : OriginalParamType(OriginalParamType), ArgIdx(ArgIdx), OriginalArgType(OriginalArgType) { } QualType OriginalParamType; unsigned ArgIdx; QualType OriginalArgType; }; TemplateDeductionResult FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, SmallVectorImpl &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, SmallVectorImpl const *OriginalCallArgs = 0); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, llvm::ArrayRef Args, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ToType, CXXConversionDecl *&Specialization, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info); /// \brief Result type of DeduceAutoType. enum DeduceAutoResult { DAR_Succeeded, DAR_Failed, DAR_FailedAlreadyDiagnosed }; DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, TypeSourceInfo *&Result); void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments); UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments, 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); void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used); void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced) { return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced); } static void MarkDeducedTemplateParameters(ASTContext &Ctx, FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced); //===--------------------------------------------------------------------===// // C++ Template Instantiation // MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = 0, bool RelativeToPrimary = false, const FunctionDecl *Pattern = 0); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { /// \brief The kind of template instantiation we are performing enum InstantiationKind { /// 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, and /// TemplateArgs/NumTemplateArguments provides the template /// arguments as specified. /// FIXME: Use a TemplateArgumentList 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 ClassTemplatePartialSpecializationDecl or /// a FunctionTemplateDecl. 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 } Kind; /// \brief The point of instantiation within the source code. SourceLocation PointOfInstantiation; /// \brief The template (or partial specialization) in which we are /// performing the instantiation, for substitutions of prior template /// arguments. NamedDecl *Template; /// \brief The entity that is being instantiated. uintptr_t Entity; /// \brief The list of template arguments we are substituting, if they /// are not part of the entity. const TemplateArgument *TemplateArgs; /// \brief The number of template arguments in TemplateArgs. unsigned 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; ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), NumTemplateArgs(0), DeductionInfo(0) {} /// \brief Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. bool isInstantiationRecord() const; friend bool operator==(const ActiveTemplateInstantiation &X, const ActiveTemplateInstantiation &Y) { if (X.Kind != Y.Kind) return false; if (X.Entity != Y.Entity) return false; switch (X.Kind) { case TemplateInstantiation: case ExceptionSpecInstantiation: return true; case PriorTemplateArgumentSubstitution: case DefaultTemplateArgumentChecking: if (X.Template != Y.Template) return false; // Fall through case DefaultTemplateArgumentInstantiation: case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: case DefaultFunctionArgumentInstantiation: return X.TemplateArgs == Y.TemplateArgs; } llvm_unreachable("Invalid InstantiationKind!"); } friend bool operator!=(const ActiveTemplateInstantiation &X, const ActiveTemplateInstantiation &Y) { return !(X == Y); } }; /// \brief List of active template instantiations. /// /// This vector is treated as a stack. As one template instantiation /// requires another template instantiation, additional /// instantiations are pushed onto the stack up to a /// user-configurable limit LangOptions::InstantiationDepth. SmallVector ActiveTemplateInstantiations; /// \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 ActiveTemplateInstantiation entries in /// \c ActiveTemplateInstantiations that are not actual instantiations and, /// therefore, should not be counted as part of the instantiation depth. unsigned NonInstantiationEntries; /// \brief The last template from which a template instantiation /// error or warning was produced. /// /// This value is used to suppress printing of redundant template /// instantiation backtraces when there are multiple errors in the /// same instantiation. FIXME: Does this belong in Sema? It's tough /// to implement it anywhere else. ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; /// \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 The stack of calls expression undergoing template instantiation. /// /// The top of this stack is used by a fixit instantiating unresolved /// function calls to fix the AST to match the textual change it prints. SmallVector CallsUndergoingInstantiation; /// \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. llvm::DenseMap > 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, 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, TemplateDecl *Template, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating a default argument in a /// template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *FunctionTemplate, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, ActiveTemplateInstantiation::InstantiationKind Kind, 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, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are substituting prior template arguments into a /// non-type or template template parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, NonTypeTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange); InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, TemplateTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, 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, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, 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. operator bool() const { return Invalid; } private: Sema &SemaRef; bool Invalid; bool SavedInNonInstantiationSFINAEContext; bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); InstantiatingTemplate(const InstantiatingTemplate&); // not implemented InstantiatingTemplate& operator=(const InstantiatingTemplate&); // not implemented }; void PrintInstantiationStack(); /// \brief Determines whether we are currently in a context where /// template argument substitution failures are not considered /// errors. /// /// \returns An empty \c llvm::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. llvm::Optional isSFINAEContext() const; /// \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 The current instantiation scope used to store local /// variables. LocalInstantiationScope *CurrentInstantiationScope; /// \brief The number of typos corrected by CorrectTypo. unsigned TyposCorrected; typedef llvm::DenseMap UnqualifiedTyposCorrectedMap; /// \brief A cache containing the results of typo correction for unqualified /// name lookup. /// /// The string is the string that we corrected to (which may be empty, if /// there was no correction), while the boolean will be true when the /// string represents a keyword. UnqualifiedTyposCorrectedMap UnqualifiedTyposCorrected; /// \brief Worker object for performing CFG-based warnings. sema::AnalysisBasedWarnings AnalysisWarnings; /// \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; /// \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; void PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); 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); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, llvm::Optional NumExpansions, bool ExpectParameterPack); bool SubstParmTypes(SourceLocation Loc, ParmVarDecl **Params, unsigned NumParams, const MultiLevelTemplateArgumentList &TemplateArgs, SmallVectorImpl &ParamTypes, SmallVectorImpl *OutParams = 0); 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 NumExprs The number of expressions in \p Exprs. /// /// \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(Expr **Exprs, unsigned NumExprs, 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); 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 = 0, LocalInstantiationScope *OuterMostScope = 0); 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); 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; Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); Decl *ActOnCompatiblityAlias( 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, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc); 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, unsigned NumElts); DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, const IdentifierLocPair *IdentList, unsigned NumElts, AttributeList *attrList); void FindProtocolDeclaration(bool WarnOnDeclarations, const IdentifierLocPair *ProtocolId, unsigned NumProtocols, SmallVectorImpl &Protocols); /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \arg PropertyTy. void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, SourceLocation Loc, unsigned &Attributes); /// Process the specified property declaration and create decls for the /// setters and getters as needed. /// \param property The property declaration being processed /// \param DC The semantic container for the property /// \param redeclaredProperty Declaration for property if redeclared /// in class extension. /// \param lexicalDC Container for redeclaredProperty. void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC, ObjCPropertyDecl *redeclaredProperty = 0, ObjCContainerDecl *lexicalDC = 0); void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, const IdentifierInfo *Name); void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl); void CompareMethodParamsInBaseAndSuper(Decl *IDecl, ObjCMethodDecl *MethodDecl, bool IsInstance); void CompareProperties(Decl *CDecl, Decl *MergeProtocols); void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID); void MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl); Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd, Decl **allMethods = 0, unsigned allNum = 0, Decl **allProperties = 0, unsigned pNum = 0, DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); Decl *ActOnProperty(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, bool *OverridingProperty, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = 0); Decl *ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar, SourceLocation PropertyIvarLoc); 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); // Helper method for ActOnClassMethod/ActOnInstanceMethod. // Will search "local" class/category implementations for a method decl. // Will also search in class's root looking for instance method. // Returns 0 if no method is found. ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel, ObjCInterfaceDecl *CDecl); ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel, ObjCInterfaceDecl *ClassDecl); ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, const ObjCObjectPointerType *OPT, bool IsInstance); ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, bool IsInstance); 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); 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, bool IsImplementation); /// \brief Check whether the given method overrides any methods in its class, /// calling \c CheckObjCMethodOverride for each overridden method. bool CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, DeclContext *DC); 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, SourceLocation KindLoc); enum PragmaPackKind { PPK_Default, // #pragma pack([n]) PPK_Show, // #pragma pack(show), only supported by MSVC. PPK_Push, // #pragma pack(push, [identifier], [n]) PPK_Pop // #pragma pack(pop, [identifier], [n]) }; enum PragmaMSStructKind { PMSST_OFF, // #pragms ms_struct off PMSST_ON // #pragms ms_struct on }; /// ActOnPragmaPack - Called on well formed #pragma pack(...). void ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, Expr *Alignment, SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc); /// ActOnPragmaMSStruct - Called on well formed #pragms ms_struct [on|off]. void ActOnPragmaMSStruct(PragmaMSStructKind Kind); /// 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 void ActOnPragmaFPContract(tok::OnOffSwitch OOS); /// 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); /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E); void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T); /// \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 = 0, 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); // DefaultFunctionArrayConversion - converts functions and arrays // to their respective pointers (C99 6.3.2.1). ExprResult DefaultFunctionArrayConversion(Expr *E); // DefaultFunctionArrayLvalueConversion - converts functions and // arrays to their respective pointers and performs the // lvalue-to-rvalue conversion. ExprResult DefaultFunctionArrayLvalueConversion(Expr *E); // 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); // Used for emitting the right warning by DefaultVariadicArgumentPromotion enum VariadicCallType { VariadicFunction, VariadicBlock, VariadicMethod, VariadicConstructor, VariadicDoesNotApply }; /// GatherArgumentsForCall - Collector argument expressions for various /// form of call prototypes. bool GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, const FunctionProtoType *Proto, unsigned FirstProtoArg, Expr **Args, unsigned NumArgs, SmallVector &AllArgs, VariadicCallType CallType = VariadicDoesNotApply, bool AllowExplicit = false); // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will warn 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, /// IncompatiblePointer - 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 = 0); /// 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 prepare for a conversion of the /// RHS to the LHS type. AssignConvertType CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, CastKind &Kind); // CheckSingleAssignmentConstraints - Currently used by // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, // this routine performs the default function/array converions. AssignConvertType CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS, bool Diagnose = 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 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, unsigned Opc, QualType* CompLHSTy = 0); QualType CheckSubtractionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy = 0); QualType CheckShiftOperands( // C99 6.5.7 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc, bool IsCompAssign = false); QualType CheckCompareOperands( // C99 6.5.8/9 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned OpaqueOpc, bool isRelational); QualType CheckBitwiseOperands( // C99 6.5.[10...12] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign = false); QualType CheckLogicalOperands( // C99 6.5.[13,14] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned 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 *NonStandardCompositeType = 0); QualType FindCompositePointerType(SourceLocation Loc, ExprResult &E1, ExprResult &E2, bool *NonStandardCompositeType = 0) { Expr *E1Tmp = E1.take(), *E2Tmp = E2.take(); QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp, NonStandardCompositeType); E1 = Owned(E1Tmp); E2 = Owned(E2Tmp); return Composite; } QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc); bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, SourceLocation QuestionLoc); /// type checking for vector binary operators. QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign); QualType GetSignedVectorType(QualType V); QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool isRelational); QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc); /// 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_With_Added_Qualification - The two types are /// reference-compatible with added qualification, meaning that /// they are reference-compatible and the qualifiers on T1 (cv1) /// are greater than the qualifiers on T2 (cv2). Ref_Compatible_With_Added_Qualification, /// Ref_Compatible - The two types are reference-compatible and /// have equivalent qualifiers (cv1 == cv2). 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); // 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); // 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, SourceLocation LParenLoc, Expr *CastExpr, SourceLocation RParenLoc); enum ARCConversionResult { ACR_okay, ACR_unbridged }; /// \brief Checks for invalid conversions and casts between /// retainable pointers and other pointer kinds. ARCConversionResult CheckObjCARCConversion(SourceRange castRange, QualType castType, Expr *&op, CheckedConversionKind CCK); 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); /// 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, Expr **Args, unsigned NumArgs, Selector Sel, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, 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); /// 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(Expr *E, SourceLocation Loc); ExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc, Expr *SubExpr); /// 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); /// 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); /// 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, const PartialDiagnostic &Diag, bool AllowFold, const PartialDiagnostic &FoldDiag); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, const PartialDiagnostic &Diag, bool AllowFold = true) { return VerifyIntegerConstantExpression(E, Result, Diag, AllowFold, PDiag(0)); } ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result = 0); /// 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, Expr *BitWidth, bool *ZeroWidth = 0); enum CUDAFunctionTarget { CFT_Device, CFT_Global, CFT_Host, CFT_HostDevice }; CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D); bool CheckCUDATarget(CUDAFunctionTarget CallerTarget, CUDAFunctionTarget CalleeTarget); bool CheckCUDATarget(const FunctionDecl *Caller, const FunctionDecl *Callee) { return CheckCUDATarget(IdentifyCUDATarget(Caller), IdentifyCUDATarget(Callee)); } /// \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); void CodeCompletePostfixExpression(Scope *S, ExprResult LHS); void CodeCompleteTag(Scope *S, unsigned TagSpec); void CodeCompleteTypeQualifiers(DeclSpec &DS); void CodeCompleteCase(Scope *S); void CodeCompleteCall(Scope *S, Expr *Fn, llvm::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, CXXCtorInitializer** Initializers, unsigned NumInitializers); 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, IdentifierInfo **SelIdents, unsigned NumSelIdents, bool AtArgumentExpression); void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, IdentifierInfo **SelIdents, unsigned NumSelIdents, bool AtArgumentExpression, bool IsSuper = false); void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, IdentifierInfo **SelIdents, unsigned NumSelIdents, bool AtArgumentExpression, ObjCInterfaceDecl *Super = 0); void CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar); void CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents, unsigned NumSelIdents); void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, unsigned NumProtocols); 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, IdentifierInfo **SelIdents, unsigned NumSelIdents); 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 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=0, bool AllowOnePastEnd=true, bool IndexNegated=false); void CheckArrayAccess(const Expr *E); bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc, Expr **Args, unsigned NumArgs); bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); bool CheckObjCString(Expr *Arg); ExprResult CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); public: // Used by C++ template instantiation. ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); private: bool SemaBuiltinPrefetch(CallExpr *TheCall); bool SemaBuiltinObjectSize(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); enum FormatStringType { FST_Scanf, FST_Printf, FST_NSString, FST_Strftime, FST_Strfmon, FST_Kprintf, FST_Unknown }; static FormatStringType GetFormatStringType(const FormatAttr *Format); bool SemaCheckStringLiteral(const Expr *E, Expr **Args, unsigned NumArgs, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, bool inFunctionCall = true); void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr, Expr **Args, unsigned NumArgs, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, bool inFunctionCall); void CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall); void CheckFormatArguments(const FormatAttr *Format, Expr **Args, unsigned NumArgs, bool IsCXXMember, SourceLocation Loc, SourceRange Range); void CheckFormatArguments(Expr **Args, unsigned NumArgs, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, SourceLocation Loc, SourceRange range); void CheckNonNullArguments(const NonNullAttr *NonNull, const Expr * const *ExprArgs, SourceLocation CallSiteLoc); void CheckMemaccessArguments(const CallExpr *Call, unsigned BId, IdentifierInfo *FnName); void CheckStrlcpycatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckStrncatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc); void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, Expr *Init); /// \brief The parser's current scope. /// /// The parser maintains this state here. Scope *CurScope; protected: friend class Parser; friend class InitializationSequence; friend class ASTReader; friend class ASTWriter; public: /// \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; } Decl *getObjCDeclContext() const; DeclContext *getCurLexicalContext() const { return OriginalLexicalContext ? OriginalLexicalContext : CurContext; } AvailabilityResult getCurContextAvailability() const; }; /// \brief RAII object that enters a new expression evaluation context. class EnterExpressionEvaluationContext { Sema &Actions; public: EnterExpressionEvaluationContext(Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = 0, bool IsDecltype = false) : Actions(Actions) { Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, IsDecltype); } ~EnterExpressionEvaluationContext() { Actions.PopExpressionEvaluationContext(); } }; } // end namespace clang #endif Index: vendor/clang/dist/lib/Analysis/UninitializedValues.cpp =================================================================== --- vendor/clang/dist/lib/Analysis/UninitializedValues.cpp (revision 235808) +++ vendor/clang/dist/lib/Analysis/UninitializedValues.cpp (revision 235809) @@ -1,724 +1,725 @@ //==- UninitializedValues.cpp - Find Uninitialized Values -------*- C++ --*-==// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements uninitialized values analysis for source-level CFGs. // //===----------------------------------------------------------------------===// #include #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/PackedVector.h" #include "llvm/ADT/DenseMap.h" #include "clang/AST/Decl.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Analysis/Analyses/UninitializedValues.h" #include "llvm/Support/SaveAndRestore.h" using namespace clang; static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() && !vd->isExceptionVariable() && vd->getDeclContext() == dc) { QualType ty = vd->getType(); return ty->isScalarType() || ty->isVectorType(); } return false; } //------------------------------------------------------------------------====// // DeclToIndex: a mapping from Decls we track to value indices. //====------------------------------------------------------------------------// namespace { class DeclToIndex { llvm::DenseMap map; public: DeclToIndex() {} /// Compute the actual mapping from declarations to bits. void computeMap(const DeclContext &dc); /// Return the number of declarations in the map. unsigned size() const { return map.size(); } /// Returns the bit vector index for a given declaration. llvm::Optional getValueIndex(const VarDecl *d) const; }; } void DeclToIndex::computeMap(const DeclContext &dc) { unsigned count = 0; DeclContext::specific_decl_iterator I(dc.decls_begin()), E(dc.decls_end()); for ( ; I != E; ++I) { const VarDecl *vd = *I; if (isTrackedVar(vd, &dc)) map[vd] = count++; } } llvm::Optional DeclToIndex::getValueIndex(const VarDecl *d) const { llvm::DenseMap::const_iterator I = map.find(d); if (I == map.end()) return llvm::Optional(); return I->second; } //------------------------------------------------------------------------====// // CFGBlockValues: dataflow values for CFG blocks. //====------------------------------------------------------------------------// // These values are defined in such a way that a merge can be done using // a bitwise OR. enum Value { Unknown = 0x0, /* 00 */ Initialized = 0x1, /* 01 */ Uninitialized = 0x2, /* 10 */ MayUninitialized = 0x3 /* 11 */ }; static bool isUninitialized(const Value v) { return v >= Uninitialized; } static bool isAlwaysUninit(const Value v) { return v == Uninitialized; } namespace { typedef llvm::PackedVector ValueVector; typedef std::pair BVPair; class CFGBlockValues { const CFG &cfg; BVPair *vals; ValueVector scratch; DeclToIndex declToIndex; ValueVector &lazyCreate(ValueVector *&bv); public: CFGBlockValues(const CFG &cfg); ~CFGBlockValues(); unsigned getNumEntries() const { return declToIndex.size(); } void computeSetOfDeclarations(const DeclContext &dc); ValueVector &getValueVector(const CFGBlock *block, const CFGBlock *dstBlock); BVPair &getValueVectors(const CFGBlock *block, bool shouldLazyCreate); void mergeIntoScratch(ValueVector const &source, bool isFirst); bool updateValueVectorWithScratch(const CFGBlock *block); bool updateValueVectors(const CFGBlock *block, const BVPair &newVals); bool hasNoDeclarations() const { return declToIndex.size() == 0; } void resetScratch(); ValueVector &getScratch() { return scratch; } ValueVector::reference operator[](const VarDecl *vd); }; } // end anonymous namespace CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) { unsigned n = cfg.getNumBlockIDs(); if (!n) return; vals = new std::pair[n]; memset((void*)vals, 0, sizeof(*vals) * n); } CFGBlockValues::~CFGBlockValues() { unsigned n = cfg.getNumBlockIDs(); if (n == 0) return; for (unsigned i = 0; i < n; ++i) { delete vals[i].first; delete vals[i].second; } delete [] vals; } void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) { declToIndex.computeMap(dc); scratch.resize(declToIndex.size()); } ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) { if (!bv) bv = new ValueVector(declToIndex.size()); return *bv; } /// This function pattern matches for a '&&' or '||' that appears at /// the beginning of a CFGBlock that also (1) has a terminator and /// (2) has no other elements. If such an expression is found, it is returned. static const BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) { if (block->empty()) return 0; - const CFGStmt *cstmt = block->front().getAs(); + CFGElement front = block->front(); + const CFGStmt *cstmt = front.getAs(); if (!cstmt) return 0; const BinaryOperator *b = dyn_cast_or_null(cstmt->getStmt()); if (!b || !b->isLogicalOp()) return 0; if (block->pred_size() == 2) { if (block->getTerminatorCondition() == b) { if (block->succ_size() == 2) return b; } else if (block->size() == 1) return b; } return 0; } ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block, const CFGBlock *dstBlock) { unsigned idx = block->getBlockID(); if (dstBlock && getLogicalOperatorInChain(block)) { if (*block->succ_begin() == dstBlock) return lazyCreate(vals[idx].first); assert(*(block->succ_begin()+1) == dstBlock); return lazyCreate(vals[idx].second); } assert(vals[idx].second == 0); return lazyCreate(vals[idx].first); } BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block, bool shouldLazyCreate) { unsigned idx = block->getBlockID(); lazyCreate(vals[idx].first); if (shouldLazyCreate) lazyCreate(vals[idx].second); return vals[idx]; } #if 0 static void printVector(const CFGBlock *block, ValueVector &bv, unsigned num) { llvm::errs() << block->getBlockID() << " :"; for (unsigned i = 0; i < bv.size(); ++i) { llvm::errs() << ' ' << bv[i]; } llvm::errs() << " : " << num << '\n'; } static void printVector(const char *name, ValueVector const &bv) { llvm::errs() << name << " : "; for (unsigned i = 0; i < bv.size(); ++i) { llvm::errs() << ' ' << bv[i]; } llvm::errs() << "\n"; } #endif void CFGBlockValues::mergeIntoScratch(ValueVector const &source, bool isFirst) { if (isFirst) scratch = source; else scratch |= source; } bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) { ValueVector &dst = getValueVector(block, 0); bool changed = (dst != scratch); if (changed) dst = scratch; #if 0 printVector(block, scratch, 0); #endif return changed; } bool CFGBlockValues::updateValueVectors(const CFGBlock *block, const BVPair &newVals) { BVPair &vals = getValueVectors(block, true); bool changed = *newVals.first != *vals.first || *newVals.second != *vals.second; *vals.first = *newVals.first; *vals.second = *newVals.second; #if 0 printVector(block, *vals.first, 1); printVector(block, *vals.second, 2); #endif return changed; } void CFGBlockValues::resetScratch() { scratch.reset(); } ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) { const llvm::Optional &idx = declToIndex.getValueIndex(vd); assert(idx.hasValue()); return scratch[idx.getValue()]; } //------------------------------------------------------------------------====// // Worklist: worklist for dataflow analysis. //====------------------------------------------------------------------------// namespace { class DataflowWorklist { SmallVector worklist; llvm::BitVector enqueuedBlocks; public: DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {} void enqueueSuccessors(const CFGBlock *block); const CFGBlock *dequeue(); }; } void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) { unsigned OldWorklistSize = worklist.size(); for (CFGBlock::const_succ_iterator I = block->succ_begin(), E = block->succ_end(); I != E; ++I) { const CFGBlock *Successor = *I; if (!Successor || enqueuedBlocks[Successor->getBlockID()]) continue; worklist.push_back(Successor); enqueuedBlocks[Successor->getBlockID()] = true; } if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) return; // Rotate the newly added blocks to the start of the worklist so that it forms // a proper queue when we pop off the end of the worklist. std::rotate(worklist.begin(), worklist.begin() + OldWorklistSize, worklist.end()); } const CFGBlock *DataflowWorklist::dequeue() { if (worklist.empty()) return 0; const CFGBlock *b = worklist.back(); worklist.pop_back(); enqueuedBlocks[b->getBlockID()] = false; return b; } //------------------------------------------------------------------------====// // Transfer function for uninitialized values analysis. //====------------------------------------------------------------------------// namespace { class FindVarResult { const VarDecl *vd; const DeclRefExpr *dr; public: FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {} const DeclRefExpr *getDeclRefExpr() const { return dr; } const VarDecl *getDecl() const { return vd; } }; class TransferFunctions : public StmtVisitor { CFGBlockValues &vals; const CFG &cfg; AnalysisDeclContext ∾ UninitVariablesHandler *handler; /// The last DeclRefExpr seen when analyzing a block. Used to /// cheat when detecting cases when the address of a variable is taken. DeclRefExpr *lastDR; /// The last lvalue-to-rvalue conversion of a variable whose value /// was uninitialized. Normally this results in a warning, but it is /// possible to either silence the warning in some cases, or we /// propagate the uninitialized value. CastExpr *lastLoad; /// For some expressions, we want to ignore any post-processing after /// visitation. bool skipProcessUses; public: TransferFunctions(CFGBlockValues &vals, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler *handler) : vals(vals), cfg(cfg), ac(ac), handler(handler), lastDR(0), lastLoad(0), skipProcessUses(false) {} void reportUninit(const DeclRefExpr *ex, const VarDecl *vd, bool isAlwaysUninit); void VisitBlockExpr(BlockExpr *be); void VisitDeclStmt(DeclStmt *ds); void VisitDeclRefExpr(DeclRefExpr *dr); void VisitUnaryOperator(UnaryOperator *uo); void VisitBinaryOperator(BinaryOperator *bo); void VisitCastExpr(CastExpr *ce); void VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); void Visit(Stmt *s); bool isTrackedVar(const VarDecl *vd) { return ::isTrackedVar(vd, cast(ac.getDecl())); } FindVarResult findBlockVarDecl(Expr *ex); void ProcessUses(Stmt *s = 0); }; } static const Expr *stripCasts(ASTContext &C, const Expr *Ex) { while (Ex) { Ex = Ex->IgnoreParenNoopCasts(C); if (const CastExpr *CE = dyn_cast(Ex)) { if (CE->getCastKind() == CK_LValueBitCast) { Ex = CE->getSubExpr(); continue; } } break; } return Ex; } void TransferFunctions::reportUninit(const DeclRefExpr *ex, const VarDecl *vd, bool isAlwaysUnit) { if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit); } FindVarResult TransferFunctions::findBlockVarDecl(Expr *ex) { if (DeclRefExpr *dr = dyn_cast(ex->IgnoreParenCasts())) if (VarDecl *vd = dyn_cast(dr->getDecl())) if (isTrackedVar(vd)) return FindVarResult(vd, dr); return FindVarResult(0, 0); } void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs) { // This represents an initialization of the 'element' value. Stmt *element = fs->getElement(); const VarDecl *vd = 0; if (DeclStmt *ds = dyn_cast(element)) { vd = cast(ds->getSingleDecl()); if (!isTrackedVar(vd)) vd = 0; } else { // Initialize the value of the reference variable. const FindVarResult &res = findBlockVarDecl(cast(element)); vd = res.getDecl(); } if (vd) vals[vd] = Initialized; } void TransferFunctions::VisitBlockExpr(BlockExpr *be) { const BlockDecl *bd = be->getBlockDecl(); for (BlockDecl::capture_const_iterator i = bd->capture_begin(), e = bd->capture_end() ; i != e; ++i) { const VarDecl *vd = i->getVariable(); if (!isTrackedVar(vd)) continue; if (i->isByRef()) { vals[vd] = Initialized; continue; } Value v = vals[vd]; if (handler && isUninitialized(v)) handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v)); } } void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { // Record the last DeclRefExpr seen. This is an lvalue computation. // We use this value to later detect if a variable "escapes" the analysis. if (const VarDecl *vd = dyn_cast(dr->getDecl())) if (isTrackedVar(vd)) { ProcessUses(); lastDR = dr; } } void TransferFunctions::VisitDeclStmt(DeclStmt *ds) { for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end(); DI != DE; ++DI) { if (VarDecl *vd = dyn_cast(*DI)) { if (isTrackedVar(vd)) { if (Expr *init = vd->getInit()) { // If the initializer consists solely of a reference to itself, we // explicitly mark the variable as uninitialized. This allows code // like the following: // // int x = x; // // to deliberately leave a variable uninitialized. Different analysis // clients can detect this pattern and adjust their reporting // appropriately, but we need to continue to analyze subsequent uses // of the variable. if (init == lastLoad) { const DeclRefExpr *DR = cast(stripCasts(ac.getASTContext(), lastLoad->getSubExpr())); if (DR->getDecl() == vd) { // int x = x; // Propagate uninitialized value, but don't immediately report // a problem. vals[vd] = Uninitialized; lastLoad = 0; lastDR = 0; if (handler) handler->handleSelfInit(vd); return; } } // All other cases: treat the new variable as initialized. // This is a minor optimization to reduce the propagation // of the analysis, since we will have already reported // the use of the uninitialized value (which visiting the // initializer). vals[vd] = Initialized; } } } } } void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) { if (bo->isAssignmentOp()) { const FindVarResult &res = findBlockVarDecl(bo->getLHS()); if (const VarDecl *vd = res.getDecl()) { ValueVector::reference val = vals[vd]; if (isUninitialized(val)) { if (bo->getOpcode() != BO_Assign) reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); else val = Initialized; } } } } void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) { switch (uo->getOpcode()) { case clang::UO_PostDec: case clang::UO_PostInc: case clang::UO_PreDec: case clang::UO_PreInc: { const FindVarResult &res = findBlockVarDecl(uo->getSubExpr()); if (const VarDecl *vd = res.getDecl()) { assert(res.getDeclRefExpr() == lastDR); // We null out lastDR to indicate we have fully processed it // and we don't want the auto-value setting in Visit(). lastDR = 0; ValueVector::reference val = vals[vd]; if (isUninitialized(val)) reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); } break; } default: break; } } void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) { if (ce->getCastKind() == CK_LValueToRValue) { const FindVarResult &res = findBlockVarDecl(ce->getSubExpr()); if (res.getDecl()) { assert(res.getDeclRefExpr() == lastDR); lastLoad = ce; } } else if (ce->getCastKind() == CK_NoOp || ce->getCastKind() == CK_LValueBitCast) { skipProcessUses = true; } else if (CStyleCastExpr *cse = dyn_cast(ce)) { if (cse->getType()->isVoidType()) { // e.g. (void) x; if (lastLoad == cse->getSubExpr()) { // Squelch any detected load of an uninitialized value if // we cast it to void. lastLoad = 0; lastDR = 0; } } } } void TransferFunctions::Visit(clang::Stmt *s) { skipProcessUses = false; StmtVisitor::Visit(s); if (!skipProcessUses) ProcessUses(s); } void TransferFunctions::ProcessUses(Stmt *s) { // This method is typically called after visiting a CFGElement statement // in the CFG. We delay processing of reporting many loads of uninitialized // values until here. if (lastLoad) { // If we just visited the lvalue-to-rvalue cast, there is nothing // left to do. if (lastLoad == s) return; const DeclRefExpr *DR = cast(stripCasts(ac.getASTContext(), lastLoad->getSubExpr())); const VarDecl *VD = cast(DR->getDecl()); // If we reach here, we may have seen a load of an uninitialized value // and it hasn't been casted to void or otherwise handled. In this // situation, report the incident. if (isUninitialized(vals[VD])) reportUninit(DR, VD, isAlwaysUninit(vals[VD])); lastLoad = 0; if (DR == lastDR) { lastDR = 0; return; } } // Any other uses of 'lastDR' involve taking an lvalue of variable. // In this case, it "escapes" the analysis. if (lastDR && lastDR != s) { vals[cast(lastDR->getDecl())] = Initialized; lastDR = 0; } } //------------------------------------------------------------------------====// // High-level "driver" logic for uninitialized values analysis. //====------------------------------------------------------------------------// static bool runOnBlock(const CFGBlock *block, const CFG &cfg, AnalysisDeclContext &ac, CFGBlockValues &vals, llvm::BitVector &wasAnalyzed, UninitVariablesHandler *handler = 0) { wasAnalyzed[block->getBlockID()] = true; if (const BinaryOperator *b = getLogicalOperatorInChain(block)) { CFGBlock::const_pred_iterator itr = block->pred_begin(); BVPair vA = vals.getValueVectors(*itr, false); ++itr; BVPair vB = vals.getValueVectors(*itr, false); BVPair valsAB; if (b->getOpcode() == BO_LAnd) { // Merge the 'F' bits from the first and second. vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true); vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false); valsAB.first = vA.first; valsAB.second = &vals.getScratch(); } else { // Merge the 'T' bits from the first and second. assert(b->getOpcode() == BO_LOr); vals.mergeIntoScratch(*vA.first, true); vals.mergeIntoScratch(*vB.first, false); valsAB.first = &vals.getScratch(); valsAB.second = vA.second ? vA.second : vA.first; } return vals.updateValueVectors(block, valsAB); } // Default behavior: merge in values of predecessor blocks. vals.resetScratch(); bool isFirst = true; for (CFGBlock::const_pred_iterator I = block->pred_begin(), E = block->pred_end(); I != E; ++I) { const CFGBlock *pred = *I; if (wasAnalyzed[pred->getBlockID()]) { vals.mergeIntoScratch(vals.getValueVector(pred, block), isFirst); isFirst = false; } } // Apply the transfer function. TransferFunctions tf(vals, cfg, ac, handler); for (CFGBlock::const_iterator I = block->begin(), E = block->end(); I != E; ++I) { if (const CFGStmt *cs = dyn_cast(&*I)) { tf.Visit(const_cast(cs->getStmt())); } } tf.ProcessUses(); return vals.updateValueVectorWithScratch(block); } void clang::runUninitializedVariablesAnalysis( const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats) { CFGBlockValues vals(cfg); vals.computeSetOfDeclarations(dc); if (vals.hasNoDeclarations()) return; stats.NumVariablesAnalyzed = vals.getNumEntries(); // Mark all variables uninitialized at the entry. const CFGBlock &entry = cfg.getEntry(); for (CFGBlock::const_succ_iterator i = entry.succ_begin(), e = entry.succ_end(); i != e; ++i) { if (const CFGBlock *succ = *i) { ValueVector &vec = vals.getValueVector(&entry, succ); const unsigned n = vals.getNumEntries(); for (unsigned j = 0; j < n ; ++j) { vec[j] = Uninitialized; } } } // Proceed with the workist. DataflowWorklist worklist(cfg); llvm::BitVector previouslyVisited(cfg.getNumBlockIDs()); worklist.enqueueSuccessors(&cfg.getEntry()); llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false); wasAnalyzed[cfg.getEntry().getBlockID()] = true; while (const CFGBlock *block = worklist.dequeue()) { // Did the block change? bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed); ++stats.NumBlockVisits; if (changed || !previouslyVisited[block->getBlockID()]) worklist.enqueueSuccessors(block); previouslyVisited[block->getBlockID()] = true; } // Run through the blocks one more time, and report uninitialized variabes. for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { const CFGBlock *block = *BI; if (wasAnalyzed[block->getBlockID()]) { runOnBlock(block, cfg, ac, vals, wasAnalyzed, &handler); ++stats.NumBlockVisits; } } } UninitVariablesHandler::~UninitVariablesHandler() {} Index: vendor/clang/dist/lib/Basic/Version.cpp =================================================================== --- vendor/clang/dist/lib/Basic/Version.cpp (revision 235808) +++ vendor/clang/dist/lib/Basic/Version.cpp (revision 235809) @@ -1,144 +1,144 @@ //===- Version.cpp - Clang Version Number -----------------------*- 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 several version-related utility functions for Clang. // //===----------------------------------------------------------------------===// #include "clang/Basic/Version.h" #include "clang/Basic/LLVM.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Config/config.h" #include #include namespace clang { std::string getClangRepositoryPath() { #if defined(CLANG_REPOSITORY_STRING) return CLANG_REPOSITORY_STRING; #else #ifdef SVN_REPOSITORY StringRef URL(SVN_REPOSITORY); #else StringRef URL(""); #endif // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us // pick up a tag in an SVN export, for example. - static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_31/lib/Basic/Version.cpp $"); + static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_31/final/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); } // Strip off version from a build from an integration branch. URL = URL.slice(0, URL.find("/src/tools/clang")); // Trim path prefix off, assuming path came from standard cfe path. size_t Start = URL.find("cfe/"); if (Start != StringRef::npos) URL = URL.substr(Start + 4); return URL; #endif } std::string getLLVMRepositoryPath() { #ifdef LLVM_REPOSITORY StringRef URL(LLVM_REPOSITORY); #else StringRef URL(""); #endif // Trim path prefix off, assuming path came from standard llvm path. // Leave "llvm/" prefix to distinguish the following llvm revision from the // clang revision. size_t Start = URL.find("llvm/"); if (Start != StringRef::npos) URL = URL.substr(Start); return URL; } std::string getClangRevision() { #ifdef SVN_REVISION return SVN_REVISION; #else return ""; #endif } std::string getLLVMRevision() { #ifdef LLVM_REVISION return LLVM_REVISION; #else return ""; #endif } std::string getClangFullRepositoryVersion() { std::string buf; llvm::raw_string_ostream OS(buf); std::string Path = getClangRepositoryPath(); std::string Revision = getClangRevision(); if (!Path.empty() || !Revision.empty()) { OS << '('; if (!Path.empty()) OS << Path; if (!Revision.empty()) { if (!Path.empty()) OS << ' '; OS << Revision; } OS << ')'; } // Support LLVM in a separate repository. std::string LLVMRev = getLLVMRevision(); if (!LLVMRev.empty() && LLVMRev != Revision) { OS << " ("; std::string LLVMRepo = getLLVMRepositoryPath(); if (!LLVMRepo.empty()) OS << LLVMRepo << ' '; OS << LLVMRev << ')'; } return OS.str(); } std::string getClangFullVersion() { std::string buf; llvm::raw_string_ostream OS(buf); #ifdef CLANG_VENDOR OS << CLANG_VENDOR; #endif OS << "clang version " CLANG_VERSION_STRING " " << getClangFullRepositoryVersion(); // If vendor supplied, include the base LLVM version as well. #ifdef CLANG_VENDOR OS << " (based on LLVM " << PACKAGE_VERSION << ")"; #endif return OS.str(); } std::string getClangFullCPPVersion() { // The version string we report in __VERSION__ is just a compacted version of // the one we report on the command line. std::string buf; llvm::raw_string_ostream OS(buf); #ifdef CLANG_VENDOR OS << CLANG_VENDOR; #endif OS << "Clang " CLANG_VERSION_STRING " (" << getClangFullRepositoryVersion() << ')'; return OS.str(); } } // end namespace clang Index: vendor/clang/dist/lib/Driver/ToolChains.cpp =================================================================== --- vendor/clang/dist/lib/Driver/ToolChains.cpp (revision 235808) +++ vendor/clang/dist/lib/Driver/ToolChains.cpp (revision 235809) @@ -1,2332 +1,2334 @@ //===--- 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 "ToolChains.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/ObjCRuntime.h" #include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" #include "clang/Basic/Version.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" #include "llvm/Support/system_error.h" #include // ::getenv #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; /// Darwin - Darwin tool chain for i386 and x86_64. Darwin::Darwin(const Driver &D, const llvm::Triple& Triple) : ToolChain(D, Triple), TargetInitialized(false), ARCRuntimeForSimulator(ARCSimulator_None), LibCXXForSimulator(LibCXXSimulator_None) { // Compute the initial Darwin version from the triple unsigned Major, Minor, Micro; if (!Triple.getMacOSXVersion(Major, Minor, Micro)) getDriver().Diag(diag::err_drv_invalid_darwin_version) << Triple.getOSName(); llvm::raw_string_ostream(MacosxVersionMin) << Major << '.' << Minor << '.' << Micro; // FIXME: DarwinVersion is only used to find GCC's libexec directory. // It should be removed when we stop supporting that. DarwinVersion[0] = Minor + 4; DarwinVersion[1] = Micro; DarwinVersion[2] = 0; } types::ID Darwin::LookupTypeForExtension(const char *Ext) const { types::ID Ty = types::lookupTypeForExtension(Ext); // Darwin always preprocesses assembly files (unless -x is used explicitly). if (Ty == types::TY_PP_Asm) return types::TY_Asm; return Ty; } bool Darwin::HasNativeLLVMSupport() const { return true; } bool Darwin::hasARCRuntime() const { // FIXME: Remove this once there is a proper way to detect an ARC runtime // for the simulator. switch (ARCRuntimeForSimulator) { case ARCSimulator_None: break; case ARCSimulator_HasARCRuntime: return true; case ARCSimulator_NoARCRuntime: return false; } if (isTargetIPhoneOS()) return !isIPhoneOSVersionLT(5); else return !isMacosxVersionLT(10, 7); } bool Darwin::hasSubscriptingRuntime() const { return !isTargetIPhoneOS() && !isMacosxVersionLT(10, 8); } /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. void Darwin::configureObjCRuntime(ObjCRuntime &runtime) const { if (runtime.getKind() != ObjCRuntime::NeXT) return ToolChain::configureObjCRuntime(runtime); runtime.HasARC = runtime.HasWeak = hasARCRuntime(); runtime.HasSubscripting = hasSubscriptingRuntime(); // So far, objc_terminate is only available in iOS 5. // FIXME: do the simulator logic properly. if (!ARCRuntimeForSimulator && isTargetIPhoneOS()) runtime.HasTerminate = !isIPhoneOSVersionLT(5); else runtime.HasTerminate = false; } /// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. bool Darwin::hasBlocksRuntime() const { if (isTargetIPhoneOS()) return !isIPhoneOSVersionLT(3, 2); else return !isMacosxVersionLT(10, 6); } static const char *GetArmArchForMArch(StringRef Value) { return llvm::StringSwitch(Value) .Case("armv6k", "armv6") .Case("armv5tej", "armv5") .Case("xscale", "xscale") .Case("armv4t", "armv4t") .Case("armv7", "armv7") .Cases("armv7a", "armv7-a", "armv7") .Cases("armv7r", "armv7-r", "armv7") .Cases("armv7m", "armv7-m", "armv7") .Default(0); } static const char *GetArmArchForMCpu(StringRef Value) { return llvm::StringSwitch(Value) .Cases("arm9e", "arm946e-s", "arm966e-s", "arm968e-s", "arm926ej-s","armv5") .Cases("arm10e", "arm10tdmi", "armv5") .Cases("arm1020t", "arm1020e", "arm1022e", "arm1026ej-s", "armv5") .Case("xscale", "xscale") .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "cortex-m0", "armv6") .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "armv7") .Default(0); } StringRef Darwin::getDarwinArchName(const ArgList &Args) const { switch (getTriple().getArch()) { default: return getArchName(); case llvm::Triple::thumb: case llvm::Triple::arm: { if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) return Arch; if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) return Arch; return "arm"; } } } Darwin::~Darwin() { // Free tool implementations. for (llvm::DenseMap::iterator it = Tools.begin(), ie = Tools.end(); it != ie; ++it) delete it->second; } std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); // If the target isn't initialized (e.g., an unknown Darwin platform, return // the default triple). if (!isTargetInitialized()) return Triple.getTriple(); SmallString<16> Str; Str += isTargetIPhoneOS() ? "ios" : "macosx"; Str += getTargetVersion().getAsString(); Triple.setOSName(Str); return Triple.getTriple(); } void Generic_ELF::anchor() {} Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) { // Fallback to llvm-gcc for i386 kext compiles, we don't support that ABI. if (Inputs.size() == 1 && types::isCXX(Inputs[0]->getType()) && getTriple().isOSDarwin() && getTriple().getArch() == llvm::Triple::x86 && (C.getArgs().getLastArg(options::OPT_fapple_kext) || C.getArgs().getLastArg(options::OPT_mkernel))) Key = JA.getKind(); else Key = Action::AnalyzeJobClass; } else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::InputClass: case Action::BindArchClass: llvm_unreachable("Invalid tool kind."); case Action::PreprocessJobClass: T = new tools::darwin::Preprocess(*this); break; case Action::AnalyzeJobClass: case Action::MigrateJobClass: T = new tools::Clang(*this); break; case Action::PrecompileJobClass: case Action::CompileJobClass: T = new tools::darwin::Compile(*this); break; case Action::AssembleJobClass: { if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::darwin::Assemble(*this); break; } case Action::LinkJobClass: T = new tools::darwin::Link(*this); break; case Action::LipoJobClass: T = new tools::darwin::Lipo(*this); break; case Action::DsymutilJobClass: T = new tools::darwin::Dsymutil(*this); break; case Action::VerifyJobClass: T = new tools::darwin::VerifyDebug(*this); break; } } return *T; } DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple) : Darwin(D, Triple) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); // We expect 'as', 'ld', etc. to be adjacent to our install dir. getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); // For fallback, we need to know how to find the GCC cc1 executables, so we // also add the GCC libexec paths. This is legacy code that can be removed // once fallback is no longer useful. AddGCCLibexecPath(DarwinVersion[0]); AddGCCLibexecPath(DarwinVersion[0] - 2); AddGCCLibexecPath(DarwinVersion[0] - 1); AddGCCLibexecPath(DarwinVersion[0] + 1); AddGCCLibexecPath(DarwinVersion[0] + 2); } void DarwinClang::AddGCCLibexecPath(unsigned darwinVersion) { std::string ToolChainDir = "i686-apple-darwin"; ToolChainDir += llvm::utostr(darwinVersion); ToolChainDir += "/4.2.1"; std::string Path = getDriver().Dir; Path += "/../llvm-gcc-4.2/libexec/gcc/"; Path += ToolChainDir; getProgramPaths().push_back(Path); Path = "/usr/llvm-gcc-4.2/libexec/gcc/"; Path += ToolChainDir; getProgramPaths().push_back(Path); } void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // The Clang toolchain uses explicit paths for internal libraries. // Unfortunately, we still might depend on a few of the libraries that are // only available in the gcc library directory (in particular // libstdc++.dylib). For now, hardcode the path to the known install location. // FIXME: This should get ripped out someday. However, when building on // 10.6 (darwin10), we're still relying on this to find libstdc++.dylib. llvm::sys::Path P(getDriver().Dir); P.eraseComponent(); // .../usr/bin -> ../usr P.appendComponent("llvm-gcc-4.2"); P.appendComponent("lib"); P.appendComponent("gcc"); switch (getTriple().getArch()) { default: llvm_unreachable("Invalid Darwin arch!"); case llvm::Triple::x86: case llvm::Triple::x86_64: P.appendComponent("i686-apple-darwin10"); break; case llvm::Triple::arm: case llvm::Triple::thumb: P.appendComponent("arm-apple-darwin10"); break; case llvm::Triple::ppc: case llvm::Triple::ppc64: P.appendComponent("powerpc-apple-darwin10"); break; } P.appendComponent("4.2.1"); // Determine the arch specific GCC subdirectory. const char *ArchSpecificDir = 0; switch (getTriple().getArch()) { default: break; case llvm::Triple::arm: case llvm::Triple::thumb: { std::string Triple = ComputeLLVMTriple(Args); StringRef TripleStr = Triple; if (TripleStr.startswith("armv5") || TripleStr.startswith("thumbv5")) ArchSpecificDir = "v5"; else if (TripleStr.startswith("armv6") || TripleStr.startswith("thumbv6")) ArchSpecificDir = "v6"; else if (TripleStr.startswith("armv7") || TripleStr.startswith("thumbv7")) ArchSpecificDir = "v7"; break; } case llvm::Triple::ppc64: ArchSpecificDir = "ppc64"; break; case llvm::Triple::x86_64: ArchSpecificDir = "x86_64"; break; } if (ArchSpecificDir) { P.appendComponent(ArchSpecificDir); bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) CmdArgs.push_back(Args.MakeArgString("-L" + P.str())); P.eraseComponent(); } bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) CmdArgs.push_back(Args.MakeArgString("-L" + P.str())); } void DarwinClang::AddLinkARCArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("-force_load"); llvm::sys::Path P(getDriver().ClangExecutable); P.eraseComponent(); // 'clang' P.eraseComponent(); // 'bin' P.appendComponent("lib"); P.appendComponent("arc"); P.appendComponent("libarclite_"); std::string s = P.str(); // Mash in the platform. if (isTargetIOSSimulator()) s += "iphonesimulator"; else if (isTargetIPhoneOS()) s += "iphoneos"; // FIXME: Remove this once we depend fully on -mios-simulator-version-min. else if (ARCRuntimeForSimulator != ARCSimulator_None) s += "iphonesimulator"; else s += "macosx"; s += ".a"; CmdArgs.push_back(Args.MakeArgString(s)); } void DarwinClang::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, const char *DarwinStaticLib) const { llvm::sys::Path P(getDriver().ResourceDir); P.appendComponent("lib"); P.appendComponent("darwin"); P.appendComponent(DarwinStaticLib); // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) CmdArgs.push_back(Args.MakeArgString(P.str())); } void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Darwin only supports the compiler-rt based runtime libraries. switch (GetRuntimeLibType(Args)) { case ToolChain::RLT_CompilerRT: break; default: getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) << Args.getLastArg(options::OPT_rtlib_EQ)->getValue(Args) << "darwin"; return; } // Darwin doesn't support real static executables, don't link any runtime // libraries with -static. if (Args.hasArg(options::OPT_static)) return; // Reject -static-libgcc for now, we can deal with this when and if someone // cares. This is useful in situations where someone wants to statically link // something like libstdc++, and needs its runtime support routines. if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) { getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args); return; } // If we are building profile support, link that library in. if (Args.hasArg(options::OPT_fprofile_arcs) || Args.hasArg(options::OPT_fprofile_generate) || Args.hasArg(options::OPT_fcreate_profile) || Args.hasArg(options::OPT_coverage)) { // Select the appropriate runtime library for the target. if (isTargetIPhoneOS()) { AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_ios.a"); } else { AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_osx.a"); } } // Add ASAN runtime library, if required. Dynamic libraries and bundles // should not be linked with the runtime library. if (Args.hasFlag(options::OPT_faddress_sanitizer, options::OPT_fno_address_sanitizer, false)) { if (Args.hasArg(options::OPT_dynamiclib) || Args.hasArg(options::OPT_bundle)) return; if (isTargetIPhoneOS()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) << "-faddress-sanitizer"; } else { AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx.a"); // The ASAN runtime library requires C++ and CoreFoundation. AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-framework"); CmdArgs.push_back("CoreFoundation"); } } // Otherwise link libSystem, then the dynamic runtime library, and finally any // target specific static runtime library. CmdArgs.push_back("-lSystem"); // Select the dynamic runtime library and the target specific static library. if (isTargetIPhoneOS()) { // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, // it never went into the SDK. // Linking against libgcc_s.1 isn't needed for iOS 5.0+ if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator()) CmdArgs.push_back("-lgcc_s.1"); // We currently always need a static runtime library for iOS. AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a"); } else { // The dynamic runtime library was merged with libSystem for 10.6 and // beyond; only 10.4 and 10.5 need an additional runtime library. if (isMacosxVersionLT(10, 5)) CmdArgs.push_back("-lgcc_s.10.4"); else if (isMacosxVersionLT(10, 6)) CmdArgs.push_back("-lgcc_s.10.5"); // For OS X, we thought we would only need a static runtime library when // targeting 10.4, to provide versions of the static functions which were // omitted from 10.4.dylib. // // Unfortunately, that turned out to not be true, because Darwin system // headers can still use eprintf on i386, and it is not exported from // libSystem. Therefore, we still must provide a runtime library just for // the tiny tiny handful of projects that *might* use that symbol. if (isMacosxVersionLT(10, 5)) { AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.10.4.a"); } else { if (getTriple().getArch() == llvm::Triple::x86) AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.eprintf.a"); AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.osx.a"); } } } static inline StringRef SimulatorVersionDefineName() { return "__IPHONE_OS_VERSION_MIN_REQUIRED"; } /// \brief Parse the simulator version define: /// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9]) // and return the grouped values as integers, e.g: // __IPHONE_OS_VERSION_MIN_REQUIRED=40201 // will return Major=4, Minor=2, Micro=1. static bool GetVersionFromSimulatorDefine(StringRef define, unsigned &Major, unsigned &Minor, unsigned &Micro) { assert(define.startswith(SimulatorVersionDefineName())); StringRef name, version; llvm::tie(name, version) = define.split('='); if (version.empty()) return false; std::string verstr = version.str(); char *end; unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10); if (*end != '\0') return false; Major = num / 10000; num = num % 10000; Minor = num / 100; Micro = num % 100; return true; } void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const OptTable &Opts = getDriver().getOpts(); Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); Arg *iOSSimVersion = Args.getLastArg( options::OPT_mios_simulator_version_min_EQ); // FIXME: HACK! When compiling for the simulator we don't get a // '-miphoneos-version-min' to help us know whether there is an ARC runtime // or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED // define passed in command-line. if (!iOSVersion && !iOSSimVersion) { for (arg_iterator it = Args.filtered_begin(options::OPT_D), ie = Args.filtered_end(); it != ie; ++it) { StringRef define = (*it)->getValue(Args); if (define.startswith(SimulatorVersionDefineName())) { unsigned Major = 0, Minor = 0, Micro = 0; if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && Major < 10 && Minor < 100 && Micro < 100) { ARCRuntimeForSimulator = Major < 5 ? ARCSimulator_NoARCRuntime : ARCSimulator_HasARCRuntime; LibCXXForSimulator = Major < 5 ? LibCXXSimulator_NotAvailable : LibCXXSimulator_Available; } break; } } } if (OSXVersion && (iOSVersion || iOSSimVersion)) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) << (iOSVersion ? iOSVersion : iOSSimVersion)->getAsString(Args); iOSVersion = iOSSimVersion = 0; } else if (iOSVersion && iOSSimVersion) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << iOSVersion->getAsString(Args) << iOSSimVersion->getAsString(Args); iOSSimVersion = 0; } else if (!OSXVersion && !iOSVersion && !iOSSimVersion) { // If no deployment target was specified on the command line, check for // environment defines. StringRef OSXTarget; StringRef iOSTarget; StringRef iOSSimTarget; if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET")) OSXTarget = env; if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET")) iOSTarget = env; if (char *env = ::getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET")) iOSSimTarget = env; // If no '-miphoneos-version-min' specified on the command line and // IPHONEOS_DEPLOYMENT_TARGET is not defined, see if we can set the default // based on -isysroot. if (iOSTarget.empty()) { if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef first, second; StringRef isysroot = A->getValue(Args); llvm::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS")); if (second != "") iOSTarget = second.substr(0,3); } } // If no OSX or iOS target has been specified and we're compiling for armv7, // go ahead as assume we're targeting iOS. if (OSXTarget.empty() && iOSTarget.empty()) if (getDarwinArchName(Args) == "armv7") iOSTarget = "0.0"; // Handle conflicting deployment targets // // FIXME: Don't hardcode default here. // Do not allow conflicts with the iOS simulator target. if (!iOSSimTarget.empty() && (!OSXTarget.empty() || !iOSTarget.empty())) { getDriver().Diag(diag::err_drv_conflicting_deployment_targets) << "IOS_SIMULATOR_DEPLOYMENT_TARGET" << (!OSXTarget.empty() ? "MACOSX_DEPLOYMENT_TARGET" : "IPHONEOS_DEPLOYMENT_TARGET"); } // Allow conflicts among OSX and iOS for historical reasons, but choose the // default platform. if (!OSXTarget.empty() && !iOSTarget.empty()) { if (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::thumb) OSXTarget = ""; else iOSTarget = ""; } if (!OSXTarget.empty()) { const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget); Args.append(OSXVersion); } else if (!iOSTarget.empty()) { const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget); Args.append(iOSVersion); } else if (!iOSSimTarget.empty()) { const Option *O = Opts.getOption( options::OPT_mios_simulator_version_min_EQ); iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget); Args.append(iOSSimVersion); } else { // Otherwise, assume we are targeting OS X. const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); OSXVersion = Args.MakeJoinedArg(0, O, MacosxVersionMin); Args.append(OSXVersion); } } // Reject invalid architecture combinations. if (iOSSimVersion && (getTriple().getArch() != llvm::Triple::x86 && getTriple().getArch() != llvm::Triple::x86_64)) { getDriver().Diag(diag::err_drv_invalid_arch_for_deployment_target) << getTriple().getArchName() << iOSSimVersion->getAsString(Args); } // Set the tool chain target information. unsigned Major, Minor, Micro; bool HadExtra; if (OSXVersion) { assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!"); if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor, Micro, HadExtra) || HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSXVersion->getAsString(Args); } else { const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion; assert(Version && "Unknown target platform!"); if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor, Micro, HadExtra) || HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << Version->getAsString(Args); } bool IsIOSSim = bool(iOSSimVersion); // In GCC, the simulator historically was treated as being OS X in some // contexts, like determining the link logic, despite generally being called // with an iOS deployment target. For compatibility, we detect the // simulator as iOS + x86, and treat it differently in a few contexts. if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64)) IsIOSSim = true; setTarget(/*IsIPhoneOS=*/ !OSXVersion, Major, Minor, Micro, IsIOSSim); } void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); break; case ToolChain::CST_Libstdcxx: { // Unfortunately, -lstdc++ doesn't always exist in the standard search path; // it was previously found in the gcc lib dir. However, for all the Darwin // platforms we care about it was -lstdc++.6, so we search for that // explicitly if we can't see an obvious -lstdc++ candidate. // Check in the sysroot first. bool Exists; if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { llvm::sys::Path P(A->getValue(Args)); P.appendComponent("usr"); P.appendComponent("lib"); P.appendComponent("libstdc++.dylib"); if (llvm::sys::fs::exists(P.str(), Exists) || !Exists) { P.eraseComponent(); P.appendComponent("libstdc++.6.dylib"); if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) { CmdArgs.push_back(Args.MakeArgString(P.str())); return; } } } // Otherwise, look in the root. // FIXME: This should be removed someday when we don't have to care about // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist. if ((llvm::sys::fs::exists("/usr/lib/libstdc++.dylib", Exists) || !Exists)&& (!llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib", Exists) && Exists)){ CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); return; } // Otherwise, let the linker search. CmdArgs.push_back("-lstdc++"); break; } } } void DarwinClang::AddCCKextLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // For Darwin platforms, use the compiler-rt-based support library // instead of the gcc-provided one (which is also incidentally // only present in the gcc lib dir, which makes it hard to find). llvm::sys::Path P(getDriver().ResourceDir); P.appendComponent("lib"); P.appendComponent("darwin"); P.appendComponent("libclang_rt.cc_kext.a"); // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) CmdArgs.push_back(Args.MakeArgString(P.str())); } DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); // FIXME: We really want to get out of the tool chain level argument // translation business, as it makes the driver functionality much // more opaque. For now, we follow gcc closely solely for the // purpose of easily achieving feature parity & testability. Once we // have something that works, we should reevaluate each translation // and try to push it down into tool specific logic. for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches either the toolchain // triple arch, or the arch being bound. // // FIXME: Canonicalize name. StringRef XarchArch = A->getValue(Args, 0); if (!(XarchArch == getArchName() || (BoundArch && XarchArch == BoundArch))) continue; Arg *OriginalArg = A; unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(Args, 1)); unsigned Prev = Index; Arg *XarchArg = Opts.ParseOneArg(Args, Index); // If the argument parsing failed or more than one argument was // consumed, the -Xarch_ argument's parameter tried to consume // extra arguments. Emit an error and ignore. // // We also want to disallow any options which would alter the // driver behavior; that isn't going to work in our model. We // use isDriverOption() as an approximation, although things // like -O4 are going to slip through. if (!XarchArg || Index > Prev + 1) { getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) << A->getAsString(Args); continue; } else if (XarchArg->getOption().isDriverOption()) { getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) << A->getAsString(Args); continue; } XarchArg->setBaseArg(A); A = XarchArg; DAL->AddSynthesizedArg(A); // Linker input arguments require custom handling. The problem is that we // have already constructed the phase actions, so we can not treat them as // "input arguments". if (A->getOption().isLinkerInput()) { // Convert the argument into individual Zlinker_input_args. for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { DAL->AddSeparateArg(OriginalArg, Opts.getOption(options::OPT_Zlinker_input), A->getValue(Args, i)); } continue; } } // Sob. These is strictly gcc compatible for the time being. Apple // gcc translates options twice, which means that self-expanding // options add duplicates. switch ((options::ID) A->getOption().getID()) { default: DAL->append(A); break; case options::OPT_mkernel: case options::OPT_fapple_kext: DAL->append(A); DAL->AddFlagArg(A, Opts.getOption(options::OPT_static)); break; case options::OPT_dependency_file: DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue(Args)); break; case options::OPT_gfull: DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); DAL->AddFlagArg(A, Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols)); break; case options::OPT_gused: DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); DAL->AddFlagArg(A, Opts.getOption(options::OPT_feliminate_unused_debug_symbols)); break; case options::OPT_shared: DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib)); break; case options::OPT_fconstant_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mconstant_cfstrings)); break; case options::OPT_fno_constant_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_constant_cfstrings)); break; case options::OPT_Wnonportable_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mwarn_nonportable_cfstrings)); break; case options::OPT_Wno_nonportable_cfstrings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings)); break; case options::OPT_fpascal_strings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings)); break; case options::OPT_fno_pascal_strings: DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings)); break; } } if (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64) if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) DAL->AddJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ), "core2"); // Add the arch options based on the particular spelling of -arch, to match // how the driver driver works. if (BoundArch) { StringRef Name = BoundArch; const Option *MCpu = Opts.getOption(options::OPT_mcpu_EQ); const Option *MArch = Opts.getOption(options::OPT_march_EQ); // This code must be kept in sync with LLVM's getArchTypeForDarwinArch, // which defines the list of which architectures we accept. if (Name == "ppc") ; else if (Name == "ppc601") DAL->AddJoinedArg(0, MCpu, "601"); else if (Name == "ppc603") DAL->AddJoinedArg(0, MCpu, "603"); else if (Name == "ppc604") DAL->AddJoinedArg(0, MCpu, "604"); else if (Name == "ppc604e") DAL->AddJoinedArg(0, MCpu, "604e"); else if (Name == "ppc750") DAL->AddJoinedArg(0, MCpu, "750"); else if (Name == "ppc7400") DAL->AddJoinedArg(0, MCpu, "7400"); else if (Name == "ppc7450") DAL->AddJoinedArg(0, MCpu, "7450"); else if (Name == "ppc970") DAL->AddJoinedArg(0, MCpu, "970"); else if (Name == "ppc64") DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); else if (Name == "i386") ; else if (Name == "i486") DAL->AddJoinedArg(0, MArch, "i486"); else if (Name == "i586") DAL->AddJoinedArg(0, MArch, "i586"); else if (Name == "i686") DAL->AddJoinedArg(0, MArch, "i686"); else if (Name == "pentium") DAL->AddJoinedArg(0, MArch, "pentium"); else if (Name == "pentium2") DAL->AddJoinedArg(0, MArch, "pentium2"); else if (Name == "pentpro") DAL->AddJoinedArg(0, MArch, "pentiumpro"); else if (Name == "pentIIm3") DAL->AddJoinedArg(0, MArch, "pentium2"); else if (Name == "x86_64") DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); else if (Name == "arm") DAL->AddJoinedArg(0, MArch, "armv4t"); else if (Name == "armv4t") DAL->AddJoinedArg(0, MArch, "armv4t"); else if (Name == "armv5") DAL->AddJoinedArg(0, MArch, "armv5tej"); else if (Name == "xscale") DAL->AddJoinedArg(0, MArch, "xscale"); else if (Name == "armv6") DAL->AddJoinedArg(0, MArch, "armv6k"); else if (Name == "armv7") DAL->AddJoinedArg(0, MArch, "armv7a"); else llvm_unreachable("invalid Darwin arch"); } // Add an explicit version min argument for the deployment target. We do this // after argument translation because -Xarch_ arguments may add a version min // argument. AddDeploymentTarget(*DAL); // Validate the C++ standard library choice. CXXStdlibType Type = GetCXXStdlibType(*DAL); if (Type == ToolChain::CST_Libcxx) { switch (LibCXXForSimulator) { case LibCXXSimulator_None: // Handle non-simulator cases. if (isTargetIPhoneOS()) { if (isIPhoneOSVersionLT(5, 0)) { getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << "iOS 5.0"; } } break; case LibCXXSimulator_NotAvailable: getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << "iOS 5.0"; break; case LibCXXSimulator_Available: break; } } return DAL; } bool Darwin::IsUnwindTablesDefault() const { // FIXME: Gross; we should probably have some separate target // definition, possibly even reusing the one in clang. return getArchName() == "x86_64"; } bool Darwin::UseDwarfDebugFlags() const { if (const char *S = ::getenv("RC_DEBUG_OPTIONS")) return S[0] != '\0'; return false; } bool Darwin::UseSjLjExceptions() const { // Darwin uses SjLj exceptions on ARM. return (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::thumb); } const char *Darwin::GetDefaultRelocationModel() const { return "pic"; } const char *Darwin::GetForcedPicModel() const { if (getArchName() == "x86_64") return "pic"; return 0; } bool Darwin::SupportsProfiling() const { // Profiling instrumentation is only supported on x86. return getArchName() == "i386" || getArchName() == "x86_64"; } bool Darwin::SupportsObjCGC() const { // Garbage collection is supported everywhere except on iPhone OS. return !isTargetIPhoneOS(); } bool Darwin::SupportsObjCARC() const { return isTargetIPhoneOS() || !isMacosxVersionLT(10, 6); } std::string Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { return ComputeLLVMTriple(Args, InputType); } /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. /// \brief Parse a GCCVersion object out of a string of text. /// /// This is the primary means of forming GCCVersion objects. /*static*/ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { const GCCVersion BadVersion = { VersionText.str(), -1, -1, -1, "" }; std::pair First = VersionText.split('.'); std::pair Second = First.second.split('.'); GCCVersion GoodVersion = { VersionText.str(), -1, -1, -1, "" }; if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) return BadVersion; if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) return BadVersion; // First look for a number prefix and parse that if present. Otherwise just // stash the entire patch string in the suffix, and leave the number // unspecified. This covers versions strings such as: // 4.4 // 4.4.0 // 4.4.x // 4.4.2-rc4 // 4.4.x-patched // And retains any patch number it finds. StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); if (!PatchText.empty()) { if (unsigned EndNumber = PatchText.find_first_not_of("0123456789")) { // Try to parse the number and any suffix. if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || GoodVersion.Patch < 0) return BadVersion; GoodVersion.PatchSuffix = PatchText.substr(EndNumber).str(); } } return GoodVersion; } /// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const { if (Major < RHS.Major) return true; if (Major > RHS.Major) return false; if (Minor < RHS.Minor) return true; if (Minor > RHS.Minor) return false; // Note that we rank versions with *no* patch specified is better than ones // hard-coding a patch version. Thus if the RHS has no patch, it always // wins, and the LHS only wins if it has no patch and the RHS does have // a patch. if (RHS.Patch == -1) return true; if (Patch == -1) return false; if (Patch < RHS.Patch) return true; if (Patch > RHS.Patch) return false; if (PatchSuffix == RHS.PatchSuffix) return false; // Finally, between completely tied version numbers, the version with the // suffix loses as we prefer full releases. if (RHS.PatchSuffix.empty()) return true; return false; } static StringRef getGCCToolchainDir(const ArgList &Args) { const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain); if (A) return A->getValue(Args); return GCC_INSTALL_PREFIX; } /// \brief Construct a GCCInstallationDetector from the driver. /// /// This performs all of the autodetection and sets up the various paths. /// Once constructed, a GCCInstallationDetector is essentially immutable. /// /// FIXME: We shouldn't need an explicit TargetTriple parameter here, and /// should instead pull the target out of the driver. This is currently /// necessary because the driver doesn't store the final version of the target /// triple. Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args) : IsValid(false) { llvm::Triple MultiarchTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // The library directories which may contain GCC installations. SmallVector CandidateLibDirs, CandidateMultiarchLibDirs; // The compatible GCC triples for this particular architecture. SmallVector CandidateTripleAliases; SmallVector CandidateMultiarchTripleAliases; CollectLibDirsAndTriples(TargetTriple, MultiarchTriple, CandidateLibDirs, CandidateTripleAliases, CandidateMultiarchLibDirs, CandidateMultiarchTripleAliases); // Compute the set of prefixes for our search. SmallVector Prefixes(D.PrefixDirs.begin(), D.PrefixDirs.end()); StringRef GCCToolchainDir = getGCCToolchainDir(Args); if (GCCToolchainDir != "") { if (GCCToolchainDir.back() == '/') GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the / Prefixes.push_back(GCCToolchainDir); } else { Prefixes.push_back(D.SysRoot); Prefixes.push_back(D.SysRoot + "/usr"); Prefixes.push_back(D.InstalledDir + "/.."); } // Loop over the various components which exist and select the best GCC // installation available. GCC installs are ranked by version number. Version = GCCVersion::Parse("0.0.0"); for (unsigned i = 0, ie = Prefixes.size(); i < ie; ++i) { if (!llvm::sys::fs::exists(Prefixes[i])) continue; for (unsigned j = 0, je = CandidateLibDirs.size(); j < je; ++j) { const std::string LibDir = Prefixes[i] + CandidateLibDirs[j].str(); if (!llvm::sys::fs::exists(LibDir)) continue; for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k) ScanLibDirForGCCTriple(TargetArch, LibDir, CandidateTripleAliases[k]); } for (unsigned j = 0, je = CandidateMultiarchLibDirs.size(); j < je; ++j) { const std::string LibDir = Prefixes[i] + CandidateMultiarchLibDirs[j].str(); if (!llvm::sys::fs::exists(LibDir)) continue; for (unsigned k = 0, ke = CandidateMultiarchTripleAliases.size(); k < ke; ++k) ScanLibDirForGCCTriple(TargetArch, LibDir, CandidateMultiarchTripleAliases[k], /*NeedsMultiarchSuffix=*/true); } } } /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( const llvm::Triple &TargetTriple, const llvm::Triple &MultiarchTriple, SmallVectorImpl &LibDirs, SmallVectorImpl &TripleAliases, SmallVectorImpl &MultiarchLibDirs, SmallVectorImpl &MultiarchTripleAliases) { // Declare a bunch of static data sets that we'll select between below. These // are specifically designed to always refer to string literals to avoid any // lifetime or initialization issues. static const char *const ARMLibDirs[] = { "/lib" }; static const char *const ARMTriples[] = { "arm-linux-gnueabi", "arm-linux-androideabi" }; static const char *const X86_64LibDirs[] = { "/lib64", "/lib" }; static const char *const X86_64Triples[] = { "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux" }; static const char *const X86LibDirs[] = { "/lib32", "/lib" }; static const char *const X86Triples[] = { "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu", "i686-redhat-linux", "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", "i486-slackware-linux" }; static const char *const MIPSLibDirs[] = { "/lib" }; static const char *const MIPSTriples[] = { "mips-linux-gnu" }; static const char *const MIPSELLibDirs[] = { "/lib" }; static const char *const MIPSELTriples[] = { "mipsel-linux-gnu" }; static const char *const PPCLibDirs[] = { "/lib32", "/lib" }; static const char *const PPCTriples[] = { "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-suse-linux" }; static const char *const PPC64LibDirs[] = { "/lib64", "/lib" }; static const char *const PPC64Triples[] = { "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", "powerpc64-suse-linux", "ppc64-redhat-linux" }; switch (TargetTriple.getArch()) { case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs)); TripleAliases.append( ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples)); break; case llvm::Triple::x86_64: LibDirs.append( X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); TripleAliases.append( X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples)); MultiarchLibDirs.append( X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs)); MultiarchTripleAliases.append( X86Triples, X86Triples + llvm::array_lengthof(X86Triples)); break; case llvm::Triple::x86: LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs)); TripleAliases.append( X86Triples, X86Triples + llvm::array_lengthof(X86Triples)); MultiarchLibDirs.append( X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); MultiarchTripleAliases.append( X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples)); break; case llvm::Triple::mips: LibDirs.append( MIPSLibDirs, MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs)); TripleAliases.append( MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples)); break; case llvm::Triple::mipsel: LibDirs.append( MIPSELLibDirs, MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs)); TripleAliases.append( MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples)); break; case llvm::Triple::ppc: LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs)); TripleAliases.append( PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); MultiarchLibDirs.append( PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs)); MultiarchTripleAliases.append( PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples)); break; case llvm::Triple::ppc64: LibDirs.append( PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs)); TripleAliases.append( PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples)); MultiarchLibDirs.append( PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs)); MultiarchTripleAliases.append( PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); break; default: // By default, just rely on the standard lib directories and the original // triple. break; } // Always append the drivers target triple to the end, in case it doesn't // match any of our aliases. TripleAliases.push_back(TargetTriple.str()); // Also include the multiarch variant if it's different. if (TargetTriple.str() != MultiarchTriple.str()) MultiarchTripleAliases.push_back(MultiarchTriple.str()); } void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( llvm::Triple::ArchType TargetArch, const std::string &LibDir, StringRef CandidateTriple, bool NeedsMultiarchSuffix) { // There are various different suffixes involving the triple we // check for. We also record what is necessary to walk from each back // up to the lib directory. const std::string LibSuffixes[] = { "/gcc/" + CandidateTriple.str(), "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), // Ubuntu has a strange mis-matched pair of triples that this happens to // match. // FIXME: It may be worthwhile to generalize this and look for a second // triple. "/i386-linux-gnu/gcc/" + CandidateTriple.str() }; const std::string InstallSuffixes[] = { "/../../..", "/../../../..", "/../../../.." }; // Only look at the final, weird Ubuntu suffix for i386-linux-gnu. const unsigned NumLibSuffixes = (llvm::array_lengthof(LibSuffixes) - (TargetArch != llvm::Triple::x86)); for (unsigned i = 0; i < NumLibSuffixes; ++i) { StringRef LibSuffix = LibSuffixes[i]; llvm::error_code EC; for (llvm::sys::fs::directory_iterator LI(LibDir + LibSuffix, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->path()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); static const GCCVersion MinVersion = { "4.1.1", 4, 1, 1, "" }; if (CandidateVersion < MinVersion) continue; if (CandidateVersion <= Version) continue; // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit // libs in a subdirectory named 64. The simple logic we follow is that // *if* there is a subdirectory of the right name with crtbegin.o in it, // we use that. If not, and if not a multiarch triple, we look for // crtbegin.o without the subdirectory. StringRef MultiarchSuffix = (TargetArch == llvm::Triple::x86_64 || TargetArch == llvm::Triple::ppc64) ? "/64" : "/32"; if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) { GCCMultiarchSuffix = MultiarchSuffix.str(); } else { if (NeedsMultiarchSuffix || !llvm::sys::fs::exists(LI->path() + "/crtbegin.o")) continue; GCCMultiarchSuffix.clear(); } Version = CandidateVersion; GCCTriple.setTriple(CandidateTriple); // FIXME: We hack together the directory name here instead of // using LI to ensure stable path separators across Windows and // Linux. GCCInstallPath = LibDir + LibSuffixes[i] + "/" + VersionText.str(); GCCParentLibPath = GCCInstallPath + InstallSuffixes[i]; IsValid = true; } } } Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : ToolChain(D, Triple), GCCInstallation(getDriver(), Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); } Generic_GCC::~Generic_GCC() { // Free tool implementations. for (llvm::DenseMap::iterator it = Tools.begin(), ie = Tools.end(); it != ie; ++it) delete it->second; } Tool &Generic_GCC::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::InputClass: case Action::BindArchClass: llvm_unreachable("Invalid tool kind."); case Action::PreprocessJobClass: T = new tools::gcc::Preprocess(*this); break; case Action::PrecompileJobClass: T = new tools::gcc::Precompile(*this); break; case Action::AnalyzeJobClass: case Action::MigrateJobClass: T = new tools::Clang(*this); break; case Action::CompileJobClass: T = new tools::gcc::Compile(*this); break; case Action::AssembleJobClass: T = new tools::gcc::Assemble(*this); break; case Action::LinkJobClass: T = new tools::gcc::Link(*this); break; // This is a bit ungeneric, but the only platform using a driver // driver is Darwin. case Action::LipoJobClass: T = new tools::darwin::Lipo(*this); break; case Action::DsymutilJobClass: T = new tools::darwin::Dsymutil(*this); break; case Action::VerifyJobClass: T = new tools::darwin::VerifyDebug(*this); break; } } return *T; } bool Generic_GCC::IsUnwindTablesDefault() const { // FIXME: Gross; we should probably have some separate target // definition, possibly even reusing the one in clang. return getArchName() == "x86_64"; } const char *Generic_GCC::GetDefaultRelocationModel() const { return "static"; } const char *Generic_GCC::GetForcedPicModel() const { return 0; } /// Hexagon Toolchain Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple& Triple) : ToolChain(D, Triple) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir.c_str()) getProgramPaths().push_back(getDriver().Dir); } Hexagon_TC::~Hexagon_TC() { // Free tool implementations. for (llvm::DenseMap::iterator it = Tools.begin(), ie = Tools.end(); it != ie; ++it) delete it->second; } Tool &Hexagon_TC::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; // if (JA.getKind () == Action::CompileJobClass) // Key = JA.getKind (); // else if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); // if ((JA.getKind () == Action::CompileJobClass) // && (JA.getType () != types::TY_LTO_BC)) { // Key = JA.getKind (); // } Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::InputClass: case Action::BindArchClass: assert(0 && "Invalid tool kind."); case Action::AnalyzeJobClass: T = new tools::Clang(*this); break; case Action::AssembleJobClass: T = new tools::hexagon::Assemble(*this); break; case Action::LinkJobClass: T = new tools::hexagon::Link(*this); break; default: assert(false && "Unsupported action for Hexagon target."); } } return *T; } bool Hexagon_TC::IsUnwindTablesDefault() const { // FIXME: Gross; we should probably have some separate target // definition, possibly even reusing the one in clang. return getArchName() == "x86_64"; } const char *Hexagon_TC::GetDefaultRelocationModel() const { return "static"; } const char *Hexagon_TC::GetForcedPicModel() const { return 0; } // End Hexagon /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. /// Currently does not support anything else but compilation. TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple) : ToolChain(D, Triple) { // Path mangling to find libexec std::string Path(getDriver().Dir); Path += "/../libexec"; getProgramPaths().push_back(Path); } TCEToolChain::~TCEToolChain() { for (llvm::DenseMap::iterator it = Tools.begin(), ie = Tools.end(); it != ie; ++it) delete it->second; } bool TCEToolChain::IsMathErrnoDefault() const { return true; } bool TCEToolChain::IsUnwindTablesDefault() const { return false; } const char *TCEToolChain::GetDefaultRelocationModel() const { return "static"; } const char *TCEToolChain::GetForcedPicModel() const { return 0; } Tool &TCEToolChain::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; Key = Action::AnalyzeJobClass; Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::PreprocessJobClass: T = new tools::gcc::Preprocess(*this); break; case Action::AnalyzeJobClass: T = new tools::Clang(*this); break; default: llvm_unreachable("Unsupported action for TCE target."); } } return *T; } /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); } Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: { if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::openbsd::Assemble(*this); break; } case Action::LinkJobClass: T = new tools::openbsd::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall // back to '/usr/lib' if it doesn't exist. if ((Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::ppc) && llvm::sys::fs::exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); else getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); } Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::freebsd::Assemble(*this); break; case Action::LinkJobClass: T = new tools::freebsd::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { if (getDriver().UseStdLib) { // When targeting a 32-bit platform, try the special directory used on // 64-bit hosts, and only fall back to the main library directory if that // doesn't work. // FIXME: It'd be nicer to test if this directory exists, but I'm not sure // what all logic is needed to emulate the '=' prefix here. if (Triple.getArch() == llvm::Triple::x86) getFilePaths().push_back("=/usr/lib/i386"); getFilePaths().push_back("=/usr/lib"); } } Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::netbsd::Assemble(*this); break; case Action::LinkJobClass: T = new tools::netbsd::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// Minix - Minix tool chain which can call as(1) and ld(1) directly. Minix::Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); } Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: T = new tools::minix::Assemble(*this); break; case Action::LinkJobClass: T = new tools::minix::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly. AuroraUX::AuroraUX(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_GCC(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/sfw/lib"); getFilePaths().push_back("/opt/gcc4/lib"); getFilePaths().push_back("/opt/gcc4/lib/gcc/i386-pc-solaris2.11/4.2.4"); } Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: T = new tools::auroraux::Assemble(*this); break; case Action::LinkJobClass: T = new tools::auroraux::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. Solaris::Solaris(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_GCC(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); } Tool &Solaris::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: T = new tools::solaris::Assemble(*this); break; case Action::LinkJobClass: T = new tools::solaris::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } /// Linux toolchain (very bare-bones at the moment). enum LinuxDistro { ArchLinux, DebianLenny, DebianSqueeze, DebianWheezy, Exherbo, RHEL4, RHEL5, RHEL6, Fedora13, Fedora14, Fedora15, Fedora16, FedoraRawhide, OpenSuse11_3, OpenSuse11_4, OpenSuse12_1, + OpenSuse12_2, UbuntuHardy, UbuntuIntrepid, UbuntuJaunty, UbuntuKarmic, UbuntuLucid, UbuntuMaverick, UbuntuNatty, UbuntuOneiric, UbuntuPrecise, UnknownDistro }; static bool IsRedhat(enum LinuxDistro Distro) { return (Distro >= Fedora13 && Distro <= FedoraRawhide) || (Distro >= RHEL4 && Distro <= RHEL6); } static bool IsOpenSuse(enum LinuxDistro Distro) { - return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_1; + return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_2; } static bool IsDebian(enum LinuxDistro Distro) { return Distro >= DebianLenny && Distro <= DebianWheezy; } static bool IsUbuntu(enum LinuxDistro Distro) { return Distro >= UbuntuHardy && Distro <= UbuntuPrecise; } static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { OwningPtr File; if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) { StringRef Data = File.get()->getBuffer(); SmallVector Lines; Data.split(Lines, "\n"); LinuxDistro Version = UnknownDistro; for (unsigned i = 0, s = Lines.size(); i != s; ++i) if (Version == UnknownDistro && Lines[i].startswith("DISTRIB_CODENAME=")) Version = llvm::StringSwitch(Lines[i].substr(17)) .Case("hardy", UbuntuHardy) .Case("intrepid", UbuntuIntrepid) .Case("jaunty", UbuntuJaunty) .Case("karmic", UbuntuKarmic) .Case("lucid", UbuntuLucid) .Case("maverick", UbuntuMaverick) .Case("natty", UbuntuNatty) .Case("oneiric", UbuntuOneiric) .Case("precise", UbuntuPrecise) .Default(UnknownDistro); return Version; } if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) { StringRef Data = File.get()->getBuffer(); if (Data.startswith("Fedora release 16")) return Fedora16; else if (Data.startswith("Fedora release 15")) return Fedora15; else if (Data.startswith("Fedora release 14")) return Fedora14; else if (Data.startswith("Fedora release 13")) return Fedora13; else if (Data.startswith("Fedora release") && Data.find("Rawhide") != StringRef::npos) return FedoraRawhide; else if (Data.startswith("Red Hat Enterprise Linux") && Data.find("release 6") != StringRef::npos) return RHEL6; else if ((Data.startswith("Red Hat Enterprise Linux") || Data.startswith("CentOS")) && Data.find("release 5") != StringRef::npos) return RHEL5; else if ((Data.startswith("Red Hat Enterprise Linux") || Data.startswith("CentOS")) && Data.find("release 4") != StringRef::npos) return RHEL4; return UnknownDistro; } if (!llvm::MemoryBuffer::getFile("/etc/debian_version", File)) { StringRef Data = File.get()->getBuffer(); if (Data[0] == '5') return DebianLenny; else if (Data.startswith("squeeze/sid") || Data[0] == '6') return DebianSqueeze; else if (Data.startswith("wheezy/sid") || Data[0] == '7') return DebianWheezy; return UnknownDistro; } if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) return llvm::StringSwitch(File.get()->getBuffer()) .StartsWith("openSUSE 11.3", OpenSuse11_3) .StartsWith("openSUSE 11.4", OpenSuse11_4) .StartsWith("openSUSE 12.1", OpenSuse12_1) + .StartsWith("openSUSE 12.2", OpenSuse12_2) .Default(UnknownDistro); bool Exists; if (!llvm::sys::fs::exists("/etc/exherbo-release", Exists) && Exists) return Exherbo; if (!llvm::sys::fs::exists("/etc/arch-release", Exists) && Exists) return ArchLinux; return UnknownDistro; } /// \brief Get our best guess at the multiarch triple for a target. /// /// Debian-based systems are starting to use a multiarch setup where they use /// a target-triple directory in the library and header search paths. /// Unfortunately, this triple does not align with the vanilla target triple, /// so we provide a rough mapping here. static std::string getMultiarchTriple(const llvm::Triple TargetTriple, StringRef SysRoot) { // For most architectures, just use whatever we have rather than trying to be // clever. switch (TargetTriple.getArch()) { default: return TargetTriple.str(); // We use the existence of '/lib/' as a directory to detect some // common linux triples that don't quite match the Clang triple for both // 32-bit and 64-bit targets. Multiarch fixes its install triples to these // regardless of what the actual target triple is. case llvm::Triple::x86: if (llvm::sys::fs::exists(SysRoot + "/lib/i386-linux-gnu")) return "i386-linux-gnu"; return TargetTriple.str(); case llvm::Triple::x86_64: if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu")) return "x86_64-linux-gnu"; return TargetTriple.str(); case llvm::Triple::mips: if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu")) return "mips-linux-gnu"; return TargetTriple.str(); case llvm::Triple::mipsel: if (llvm::sys::fs::exists(SysRoot + "/lib/mipsel-linux-gnu")) return "mipsel-linux-gnu"; return TargetTriple.str(); case llvm::Triple::ppc: if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnu")) return "powerpc-linux-gnu"; return TargetTriple.str(); case llvm::Triple::ppc64: if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64-linux-gnu")) return "powerpc64-linux-gnu"; return TargetTriple.str(); } } static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str()); } Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { llvm::Triple::ArchType Arch = Triple.getArch(); const std::string &SysRoot = getDriver().SysRoot; // OpenSuse stores the linker with the compiler, add that to the search // path. ToolChain::path_list &PPaths = getProgramPaths(); PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + GCCInstallation.getTriple().str() + "/bin").str()); Linker = GetProgramPath("ld"); LinuxDistro Distro = DetectLinuxDistro(Arch); if (IsOpenSuse(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) ExtraOpts.push_back("-X"); const bool IsMips = Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::ANDROIDEABI; // Do not use 'gnu' hash style for Mips targets because .gnu.hash // and the MIPS ABI require .dynsym to be sorted in different ways. // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. if (!IsMips && !IsAndroid) { if (IsRedhat(Distro) || IsOpenSuse(Distro) || (IsUbuntu(Distro) && Distro >= UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); if (IsDebian(Distro) || IsOpenSuse(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty || Distro == UbuntuKarmic) ExtraOpts.push_back("--hash-style=both"); } if (IsRedhat(Distro)) ExtraOpts.push_back("--no-add-needed"); if (Distro == DebianSqueeze || Distro == DebianWheezy || IsOpenSuse(Distro) || (IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) || (IsUbuntu(Distro) && Distro >= UbuntuKarmic)) ExtraOpts.push_back("--build-id"); if (IsOpenSuse(Distro)) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which // the GCC driver itself uses, as this is part of the GCC-compatible driver. // This was determined by running GCC in a fake filesystem, creating all // possible permutations of these directories, and seeing which ones it added // to the link paths. path_list &Paths = getFilePaths(); const std::string Multilib = Triple.isArch32Bit() ? "lib32" : "lib64"; const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot); // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = GCCInstallation.getParentLibPath(); addPathIfExists((GCCInstallation.getInstallPath() + GCCInstallation.getMultiarchSuffix()), Paths); // If the GCC installation we found is inside of the sysroot, we want to // prefer libraries installed in the parent prefix of the GCC installation. // It is important to *not* use these paths when the GCC installation is // outside of the system root as that can pick up unintended libraries. // This usually happens when there is an external cross compiler on the // host system, and a more minimal sysroot available that is the target of // the cross. if (StringRef(LibPath).startswith(SysRoot)) { addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib, Paths); addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); addPathIfExists(LibPath + "/../" + Multilib, Paths); } } addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths); // Try walking via the GCC triple path in case of multiarch GCC // installations with strange symlinks. if (GCCInstallation.isValid()) addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + "/../../" + Multilib, Paths); // Add the non-multilib suffixed paths (if potentially different). if (GCCInstallation.isValid()) { const std::string &LibPath = GCCInstallation.getParentLibPath(); const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); if (!GCCInstallation.getMultiarchSuffix().empty()) addPathIfExists(GCCInstallation.getInstallPath(), Paths); if (StringRef(LibPath).startswith(SysRoot)) { addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths); addPathIfExists(LibPath, Paths); } } addPathIfExists(SysRoot + "/lib", Paths); addPathIfExists(SysRoot + "/usr/lib", Paths); } bool Linux::HasNativeLLVMSupport() const { return true; } Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIntegratedAssemblerDefault()); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: if (UseIntegratedAs) T = new tools::ClangAs(*this); else T = new tools::linuxtools::Assemble(*this); break; case Action::LinkJobClass: T = new tools::linuxtools::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); if (DriverArgs.hasArg(options::OPT_nostdinc)) return; if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include"); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { llvm::sys::Path P(D.ResourceDir); P.appendComponent("include"); addSystemInclude(DriverArgs, CC1Args, P.str()); } if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; // Check for configure-time C include directories. StringRef CIncludeDirs(C_INCLUDE_DIRS); if (CIncludeDirs != "") { SmallVector dirs; CIncludeDirs.split(dirs, ":"); for (SmallVectorImpl::iterator I = dirs.begin(), E = dirs.end(); I != E; ++I) { StringRef Prefix = llvm::sys::path::is_absolute(*I) ? D.SysRoot : ""; addExternCSystemInclude(DriverArgs, CC1Args, Prefix + *I); } return; } // Lacking those, try to detect the correct set of system includes for the // target triple. // Implement generic Debian multiarch support. const StringRef X86_64MultiarchIncludeDirs[] = { "/usr/include/x86_64-linux-gnu", // FIXME: These are older forms of multiarch. It's not clear that they're // in use in any released version of Debian, so we should consider // removing them. "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64" }; const StringRef X86MultiarchIncludeDirs[] = { "/usr/include/i386-linux-gnu", // FIXME: These are older forms of multiarch. It's not clear that they're // in use in any released version of Debian, so we should consider // removing them. "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu", "/usr/include/i486-linux-gnu" }; const StringRef ARMMultiarchIncludeDirs[] = { "/usr/include/arm-linux-gnueabi" }; const StringRef MIPSMultiarchIncludeDirs[] = { "/usr/include/mips-linux-gnu" }; const StringRef MIPSELMultiarchIncludeDirs[] = { "/usr/include/mipsel-linux-gnu" }; const StringRef PPCMultiarchIncludeDirs[] = { "/usr/include/powerpc-linux-gnu" }; const StringRef PPC64MultiarchIncludeDirs[] = { "/usr/include/powerpc64-linux-gnu" }; ArrayRef MultiarchIncludeDirs; if (getTriple().getArch() == llvm::Triple::x86_64) { MultiarchIncludeDirs = X86_64MultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::x86) { MultiarchIncludeDirs = X86MultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::arm) { MultiarchIncludeDirs = ARMMultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::mips) { MultiarchIncludeDirs = MIPSMultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::mipsel) { MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::ppc) { MultiarchIncludeDirs = PPCMultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::ppc64) { MultiarchIncludeDirs = PPC64MultiarchIncludeDirs; } for (ArrayRef::iterator I = MultiarchIncludeDirs.begin(), E = MultiarchIncludeDirs.end(); I != E; ++I) { if (llvm::sys::fs::exists(D.SysRoot + *I)) { addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + *I); break; } } if (getTriple().getOS() == llvm::Triple::RTEMS) return; // Add an include of '/include' directly. This isn't provided by default by // system GCCs, but is often used with cross-compiling GCCs, and harmless to // add even when Clang is acting as-if it were a system compiler. addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); } /// \brief Helper to add the thre variant paths for a libstdc++ installation. /*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir, const ArgList &DriverArgs, ArgStringList &CC1Args) { if (!llvm::sys::fs::exists(Base)) return false; addSystemInclude(DriverArgs, CC1Args, Base); addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir); addSystemInclude(DriverArgs, CC1Args, Base + "/backward"); return true; } void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; // Check if libc++ has been enabled and provide its include paths if so. if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) { // libc++ is always installed at a fixed path on Linux currently. addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/v1"); return; } // We need a detected GCC installation on Linux to provide libstdc++'s // headers. We handled the libc++ case above. if (!GCCInstallation.isValid()) return; // By default, look for the C++ headers in an include directory adjacent to // the lib directory of the GCC installation. Note that this is expect to be // equivalent to '/usr/include/c++/X.Y' in almost all cases. StringRef LibDir = GCCInstallation.getParentLibPath(); StringRef InstallDir = GCCInstallation.getInstallPath(); StringRef Version = GCCInstallation.getVersion(); if (!addLibStdCXXIncludePaths(LibDir + "/../include/c++/" + Version, (GCCInstallation.getTriple().str() + GCCInstallation.getMultiarchSuffix()), DriverArgs, CC1Args)) { // Gentoo is weird and places its headers inside the GCC install, so if the // first attempt to find the headers fails, try this pattern. addLibStdCXXIncludePaths(InstallDir + "/include/g++-v4", (GCCInstallation.getTriple().str() + GCCInstallation.getMultiarchSuffix()), DriverArgs, CC1Args); } } /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { // Path mangling to find libexec getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); getFilePaths().push_back("/usr/lib/gcc41"); } Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); Tool *&T = Tools[Key]; if (!T) { switch (Key) { case Action::AssembleJobClass: T = new tools::dragonfly::Assemble(*this); break; case Action::LinkJobClass: T = new tools::dragonfly::Link(*this); break; default: T = &Generic_GCC::SelectTool(C, JA, Inputs); } } return *T; } Index: vendor/clang/dist/lib/Parse/ParseCXXInlineMethods.cpp =================================================================== --- vendor/clang/dist/lib/Parse/ParseCXXInlineMethods.cpp (revision 235808) +++ vendor/clang/dist/lib/Parse/ParseCXXInlineMethods.cpp (revision 235809) @@ -1,767 +1,697 @@ //===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements parsing for C++ class inline methods. // //===----------------------------------------------------------------------===// #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/AST/DeclTemplate.h" using namespace clang; /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs, ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, const VirtSpecifiers& VS, FunctionDefinitionKind DefinitionKind, ExprResult& Init) { assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) || Tok.is(tok::equal)) && "Current token not a '{', ':', '=', or 'try'!"); MultiTemplateParamsArg TemplateParams(Actions, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); Decl *FnD; D.setFunctionDefinitionKind(DefinitionKind); if (D.getDeclSpec().isFriendSpecified()) FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, move(TemplateParams)); else { FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, VS, /*HasDeferredInit=*/false); if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, true); bool TypeSpecContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; if (Init.isUsable()) Actions.AddInitializerToDecl(FnD, Init.get(), false, TypeSpecContainsAuto); else Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto); } } HandleMemberFunctionDeclDelays(D, FnD); D.complete(FnD); if (Tok.is(tok::equal)) { ConsumeToken(); if (!FnD) { SkipUntil(tok::semi); return 0; } bool Delete = false; SourceLocation KWLoc; if (Tok.is(tok::kw_delete)) { Diag(Tok, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_deleted_function : diag::ext_deleted_function); KWLoc = ConsumeToken(); Actions.SetDeclDeleted(FnD, KWLoc); Delete = true; } else if (Tok.is(tok::kw_default)) { Diag(Tok, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_defaulted_function : diag::ext_defaulted_function); KWLoc = ConsumeToken(); Actions.SetDeclDefaulted(FnD, KWLoc); } else { llvm_unreachable("function definition after = not 'delete' or 'default'"); } if (Tok.is(tok::comma)) { Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) << Delete; SkipUntil(tok::semi); } else { ExpectAndConsume(tok::semi, diag::err_expected_semi_after, Delete ? "delete" : "default", tok::semi); } return FnD; } // In delayed template parsing mode, if we are within a class template // or if we are about to parse function member template then consume // the tokens and store them for parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && ((Actions.CurContext->isDependentContext() || TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) && !Actions.IsInsideALocalClassWithinATemplateFunction())) { if (FnD) { LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD); FunctionDecl *FD = 0; if (FunctionTemplateDecl *FunTmpl = dyn_cast(FnD)) FD = FunTmpl->getTemplatedDecl(); else FD = cast(FnD); Actions.CheckForFunctionRedefinition(FD); LateParsedTemplateMap[FD] = LPT; Actions.MarkAsLateParsedTemplate(FD); LexTemplateFunctionForLateParsing(LPT->Toks); } else { CachedTokens Toks; LexTemplateFunctionForLateParsing(Toks); } return FnD; } // Consume the tokens and store them for later parsing. LexedMethod* LM = new LexedMethod(this, FnD); getCurrentClass().LateParsedDeclarations.push_back(LM); LM->TemplateScope = getCurScope()->isTemplateParamScope(); CachedTokens &Toks = LM->Toks; tok::TokenKind kind = Tok.getKind(); // Consume everything up to (and including) the left brace of the // function body. if (ConsumeAndStoreFunctionPrologue(Toks)) { // We didn't find the left-brace we expected after the // constructor initializer; we already printed an error, and it's likely // impossible to recover, so don't try to parse this method later. // If we stopped at a semicolon, consume it to avoid an extra warning. if (Tok.is(tok::semi)) ConsumeToken(); delete getCurrentClass().LateParsedDeclarations.back(); getCurrentClass().LateParsedDeclarations.pop_back(); return FnD; } else { // Consume everything up to (and including) the matching right brace. ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); } // If we're in a function-try-block, we need to store all the catch blocks. if (kind == tok::kw_try) { while (Tok.is(tok::kw_catch)) { ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); } } if (!FnD) { // If semantic analysis could not build a function declaration, // just throw away the late-parsed declaration. delete getCurrentClass().LateParsedDeclarations.back(); getCurrentClass().LateParsedDeclarations.pop_back(); } return FnD; } /// ParseCXXNonStaticMemberInitializer - We parsed and verified that the /// specified Declarator is a well formed C++ non-static data member /// declaration. Now lex its initializer and store its tokens for parsing /// after the class is complete. void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) { assert((Tok.is(tok::l_brace) || Tok.is(tok::equal)) && "Current token not a '{' or '='!"); LateParsedMemberInitializer *MI = new LateParsedMemberInitializer(this, VarD); getCurrentClass().LateParsedDeclarations.push_back(MI); CachedTokens &Toks = MI->Toks; tok::TokenKind kind = Tok.getKind(); if (kind == tok::equal) { Toks.push_back(Tok); ConsumeToken(); } if (kind == tok::l_brace) { // Begin by storing the '{' token. Toks.push_back(Tok); ConsumeBrace(); // Consume everything up to (and including) the matching right brace. ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/true); } else { // Consume everything up to (but excluding) the comma or semicolon. ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false); } // Store an artificial EOF token to ensure that we don't run off the end of // the initializer when we come to parse it. Token Eof; Eof.startToken(); Eof.setKind(tok::eof); Eof.setLocation(Tok.getLocation()); Toks.push_back(Eof); } Parser::LateParsedDeclaration::~LateParsedDeclaration() {} void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {} void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {} void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {} Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C) : Self(P), Class(C) {} Parser::LateParsedClass::~LateParsedClass() { Self->DeallocateParsedClasses(Class); } void Parser::LateParsedClass::ParseLexedMethodDeclarations() { Self->ParseLexedMethodDeclarations(*Class); } void Parser::LateParsedClass::ParseLexedMemberInitializers() { Self->ParseLexedMemberInitializers(*Class); } void Parser::LateParsedClass::ParseLexedMethodDefs() { Self->ParseLexedMethodDefs(*Class); } void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() { Self->ParseLexedMethodDeclaration(*this); } void Parser::LexedMethod::ParseLexedMethodDefs() { Self->ParseLexedMethodDef(*this); } void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() { Self->ParseLexedMemberInitializer(*this); } /// ParseLexedMethodDeclarations - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the /// stack of method declarations with some parts for which parsing was /// delayed (such as default arguments) and parse them. void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); // The current scope is still active if we're the top-level class. // Otherwise we'll need to push and enter a new scope. bool HasClassScope = !Class.TopLevelClass; ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); if (HasClassScope) Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { Class.LateParsedDeclarations[i]->ParseLexedMethodDeclarations(); } if (HasClassScope) Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); } void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // If this is a member template, introduce the template parameter scope. ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); if (LM.TemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); // Start the delayed C++ method declaration Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); // Introduce the parameters into scope and parse their default // arguments. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { // Introduce the parameter into scope. Actions.ActOnDelayedCXXMethodParameter(getCurScope(), LM.DefaultArgs[I].Param); if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { // Save the current token position. SourceLocation origLoc = Tok.getLocation(); // Parse the default argument from its saved token stream. Toks->push_back(Tok); // So that the current token doesn't get lost PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); // Consume the previously-pushed token. ConsumeAnyToken(); // Consume the '='. assert(Tok.is(tok::equal) && "Default argument not starting with '='"); SourceLocation EqualLoc = ConsumeToken(); // The argument isn't actually potentially evaluated unless it is // used. EnterExpressionEvaluationContext Eval(Actions, Sema::PotentiallyEvaluatedIfUsed, LM.DefaultArgs[I].Param); ExprResult DefArgResult; if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); DefArgResult = ParseBraceInitializer(); } else DefArgResult = ParseAssignmentExpression(); if (DefArgResult.isInvalid()) Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); else { if (Tok.is(tok::cxx_defaultarg_end)) ConsumeToken(); else Diag(Tok.getLocation(), diag::err_default_arg_unparsed); Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, DefArgResult.take()); } assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, Tok.getLocation()) && "ParseAssignmentExpression went over the default arg tokens!"); // There could be leftover tokens (e.g. because of an error). // Skip through until we reach the original token position. while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); delete Toks; LM.DefaultArgs[I].Toks = 0; } } - - // Parse a delayed exception-specification, if there is one. - if (CachedTokens *Toks = LM.ExceptionSpecTokens) { - // Save the current token position. - SourceLocation origLoc = Tok.getLocation(); - - // Parse the default argument from its saved token stream. - Toks->push_back(Tok); // So that the current token doesn't get lost - PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); - - // Consume the previously-pushed token. - ConsumeAnyToken(); - - // C++11 [expr.prim.general]p3: - // If a declaration declares a member function or member function - // template of a class X, the expression this is a prvalue of type - // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq - // and the end of the function-definition, member-declarator, or - // declarator. - CXXMethodDecl *Method; - if (FunctionTemplateDecl *FunTmpl - = dyn_cast(LM.Method)) - Method = cast(FunTmpl->getTemplatedDecl()); - else - Method = cast(LM.Method); - - Sema::CXXThisScopeRAII ThisScope(Actions, Method->getParent(), - Method->getTypeQualifiers(), - getLangOpts().CPlusPlus0x); - // Parse the exception-specification. - SourceRange SpecificationRange; - SmallVector DynamicExceptions; - SmallVector DynamicExceptionRanges; - ExprResult NoexceptExpr; - CachedTokens *ExceptionSpecTokens; - - ExceptionSpecificationType EST - = tryParseExceptionSpecification(/*Delayed=*/false, SpecificationRange, - DynamicExceptions, - DynamicExceptionRanges, NoexceptExpr, - ExceptionSpecTokens); - - // Clean up the remaining tokens. - if (Tok.is(tok::cxx_exceptspec_end)) - ConsumeToken(); - else if (EST != EST_None) - Diag(Tok.getLocation(), diag::err_except_spec_unparsed); - - // Attach the exception-specification to the method. - if (EST != EST_None) - Actions.actOnDelayedExceptionSpecification(LM.Method, EST, - SpecificationRange, - DynamicExceptions, - DynamicExceptionRanges, - NoexceptExpr.isUsable()? - NoexceptExpr.get() : 0); - - assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, - Tok.getLocation()) && - "tryParseExceptionSpecification went over the exception tokens!"); - - // There could be leftover tokens (e.g. because of an error). - // Skip through until we reach the original token position. - while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) - ConsumeAnyToken(); - - delete LM.ExceptionSpecTokens; - LM.ExceptionSpecTokens = 0; - } - PrototypeScope.Exit(); // Finish the delayed C++ method declaration. Actions.ActOnFinishDelayedCXXMethodDeclaration(getCurScope(), LM.Method); } /// ParseLexedMethodDefs - We finished parsing the member specification of a top /// (non-nested) C++ class. Now go over the stack of lexed methods that were /// collected during its parsing and parse them all. void Parser::ParseLexedMethodDefs(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); bool HasClassScope = !Class.TopLevelClass; ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { Class.LateParsedDeclarations[i]->ParseLexedMethodDefs(); } } void Parser::ParseLexedMethodDef(LexedMethod &LM) { // If this is a member template, introduce the template parameter scope. ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); if (LM.TemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); // Save the current token position. SourceLocation origLoc = Tok.getLocation(); assert(!LM.Toks.empty() && "Empty body!"); // Append the current token at the end of the new token stream so that it // doesn't get lost. LM.Toks.push_back(Tok); PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); // Consume the previously pushed token. ConsumeAnyToken(); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Inline method not starting with '{', ':' or 'try'"); // Parse the method body. Function body parsing code is similar enough // to be re-used for method bodies as well. ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); if (Tok.is(tok::kw_try)) { ParseFunctionTryBlock(LM.D, FnScope); assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, Tok.getLocation()) && "ParseFunctionTryBlock went over the cached tokens!"); // There could be leftover tokens (e.g. because of an error). // Skip through until we reach the original token position. while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); return; } if (Tok.is(tok::colon)) { ParseConstructorInitializer(LM.D); // Error recovery. if (!Tok.is(tok::l_brace)) { FnScope.Exit(); Actions.ActOnFinishFunctionBody(LM.D, 0); while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); return; } } else Actions.ActOnDefaultCtorInitializers(LM.D); ParseFunctionStatementBody(LM.D, FnScope); if (Tok.getLocation() != origLoc) { // Due to parsing error, we either went over the cached tokens or // there are still cached tokens left. If it's the latter case skip the // leftover tokens. // Since this is an uncommon situation that should be avoided, use the // expensive isBeforeInTranslationUnit call. if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), origLoc)) while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); } } /// ParseLexedMemberInitializers - We finished parsing the member specification /// of a top (non-nested) C++ class. Now go over the stack of lexed data member /// initializers that were collected during its parsing and parse them all. void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); // Set or update the scope flags. bool AlreadyHasClassScope = Class.TopLevelClass; unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); if (!AlreadyHasClassScope) Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); { // C++11 [expr.prim.general]p4: // Otherwise, if a member-declarator declares a non-static data member // (9.2) of a class X, the expression this is a prvalue of type "pointer // to X" within the optional brace-or-equal-initializer. It shall not // appear elsewhere in the member-declarator. Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, /*TypeQuals=*/(unsigned)0); for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers(); } } if (!AlreadyHasClassScope) Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); Actions.ActOnFinishDelayedMemberInitializers(Class.TagOrTemplate); } void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { if (!MI.Field || MI.Field->isInvalidDecl()) return; // Append the current token at the end of the new token stream so that it // doesn't get lost. MI.Toks.push_back(Tok); PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false); // Consume the previously pushed token. ConsumeAnyToken(); SourceLocation EqualLoc; ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, EqualLoc); Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release()); // The next token should be our artificial terminating EOF token. if (Tok.isNot(tok::eof)) { SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation); if (!EndLoc.isValid()) EndLoc = Tok.getLocation(); // No fixit; we can't recover as if there were a semicolon here. Diag(EndLoc, diag::err_expected_semi_decl_list); // Consume tokens until we hit the artificial EOF. while (Tok.isNot(tok::eof)) ConsumeAnyToken(); } ConsumeAnyToken(); } /// ConsumeAndStoreUntil - Consume and store the token at the passed token /// container until the token 'T' is reached (which gets /// consumed/stored too, if ConsumeFinalToken). /// If StopAtSemi is true, then we will stop early at a ';' character. /// Returns true if token 'T1' or 'T2' was found. /// NOTE: This is a specialized version of Parser::SkipUntil. bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, CachedTokens &Toks, bool StopAtSemi, bool ConsumeFinalToken) { // We always want this function to consume at least one token if the first // token isn't T and if not at EOF. bool isFirstTokenConsumed = true; while (1) { // If we found one of the tokens, stop and return true. if (Tok.is(T1) || Tok.is(T2)) { if (ConsumeFinalToken) { Toks.push_back(Tok); ConsumeAnyToken(); } return true; } switch (Tok.getKind()) { case tok::eof: // Ran out of tokens. return false; case tok::l_paren: // Recursively consume properly-nested parens. Toks.push_back(Tok); ConsumeParen(); ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); break; case tok::l_square: // Recursively consume properly-nested square brackets. Toks.push_back(Tok); ConsumeBracket(); ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false); break; case tok::l_brace: // Recursively consume properly-nested braces. Toks.push_back(Tok); ConsumeBrace(); ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); break; // Okay, we found a ']' or '}' or ')', which we think should be balanced. // Since the user wasn't looking for this token (if they were, it would // already be handled), this isn't balanced. If there is a LHS token at a // higher level, we will assume that this matches the unbalanced token // and return it. Otherwise, this is a spurious RHS token, which we skip. case tok::r_paren: if (ParenCount && !isFirstTokenConsumed) return false; // Matches something. Toks.push_back(Tok); ConsumeParen(); break; case tok::r_square: if (BracketCount && !isFirstTokenConsumed) return false; // Matches something. Toks.push_back(Tok); ConsumeBracket(); break; case tok::r_brace: if (BraceCount && !isFirstTokenConsumed) return false; // Matches something. Toks.push_back(Tok); ConsumeBrace(); break; case tok::code_completion: Toks.push_back(Tok); ConsumeCodeCompletionToken(); break; case tok::string_literal: case tok::wide_string_literal: case tok::utf8_string_literal: case tok::utf16_string_literal: case tok::utf32_string_literal: Toks.push_back(Tok); ConsumeStringToken(); break; case tok::semi: if (StopAtSemi) return false; // FALL THROUGH. default: // consume this token. Toks.push_back(Tok); ConsumeToken(); break; } isFirstTokenConsumed = false; } } /// \brief Consume tokens and store them in the passed token container until /// we've passed the try keyword and constructor initializers and have consumed /// the opening brace of the function body. The opening brace will be consumed /// if and only if there was no error. /// /// \return True on error. bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { if (Tok.is(tok::kw_try)) { Toks.push_back(Tok); ConsumeToken(); } bool ReadInitializer = false; if (Tok.is(tok::colon)) { // Initializers can contain braces too. Toks.push_back(Tok); ConsumeToken(); while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { if (Tok.is(tok::eof) || Tok.is(tok::semi)) return Diag(Tok.getLocation(), diag::err_expected_lbrace); // Grab the identifier. if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) return Diag(Tok.getLocation(), diag::err_expected_lparen); tok::TokenKind kind = Tok.getKind(); Toks.push_back(Tok); bool IsLParen = (kind == tok::l_paren); SourceLocation LOpen = Tok.getLocation(); if (IsLParen) { ConsumeParen(); } else { assert(kind == tok::l_brace && "Must be left paren or brace here."); ConsumeBrace(); // In C++03, this has to be the start of the function body, which // means the initializer is malformed; we'll diagnose it later. if (!getLangOpts().CPlusPlus0x) return false; } // Grab the initializer if (!ConsumeAndStoreUntil(IsLParen ? tok::r_paren : tok::r_brace, Toks, /*StopAtSemi=*/true)) { Diag(Tok, IsLParen ? diag::err_expected_rparen : diag::err_expected_rbrace); Diag(LOpen, diag::note_matching) << (IsLParen ? "(" : "{"); return true; } // Grab pack ellipsis, if present if (Tok.is(tok::ellipsis)) { Toks.push_back(Tok); ConsumeToken(); } // Grab the separating comma, if any. if (Tok.is(tok::comma)) { Toks.push_back(Tok); ConsumeToken(); } else if (Tok.isNot(tok::l_brace)) { ReadInitializer = true; break; } } } // Grab any remaining garbage to be diagnosed later. We stop when we reach a // brace: an opening one is the function body, while a closing one probably // means we've reached the end of the class. ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false); if (Tok.isNot(tok::l_brace)) { if (ReadInitializer) return Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); return Diag(Tok.getLocation(), diag::err_expected_lbrace); } Toks.push_back(Tok); ConsumeBrace(); return false; } Index: vendor/clang/dist/lib/Parse/ParseDecl.cpp =================================================================== --- vendor/clang/dist/lib/Parse/ParseDecl.cpp (revision 235808) +++ vendor/clang/dist/lib/Parse/ParseDecl.cpp (revision 235809) @@ -1,4868 +1,4860 @@ //===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// // // 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 Declaration portions of the Parser interfaces. // //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Basic/OpenCL.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; //===----------------------------------------------------------------------===// // C99 6.7: Declarations. //===----------------------------------------------------------------------===// /// ParseTypeName /// type-name: [C99 6.7.6] /// specifier-qualifier-list abstract-declarator[opt] /// /// Called type-id in C++. TypeResult Parser::ParseTypeName(SourceRange *Range, Declarator::TheContext Context, AccessSpecifier AS, Decl **OwnedType) { DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context); // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS, AS, DSC); if (OwnedType) *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0; // Parse the abstract-declarator, if present. Declarator DeclaratorInfo(DS, Context); ParseDeclarator(DeclaratorInfo); if (Range) *Range = DeclaratorInfo.getSourceRange(); if (DeclaratorInfo.isInvalidType()) return true; return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } /// isAttributeLateParsed - Return true if the attribute has arguments that /// require late parsing. static bool isAttributeLateParsed(const IdentifierInfo &II) { return llvm::StringSwitch(II.getName()) #include "clang/Parse/AttrLateParsed.inc" .Default(false); } /// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: /// attribute /// attributes attribute /// /// [GNU] attribute: /// '__attribute__' '(' '(' attribute-list ')' ')' /// /// [GNU] attribute-list: /// attrib /// attribute_list ',' attrib /// /// [GNU] attrib: /// empty /// attrib-name /// attrib-name '(' identifier ')' /// attrib-name '(' identifier ',' nonempty-expr-list ')' /// attrib-name '(' argument-expression-list [C99 6.5.2] ')' /// /// [GNU] attrib-name: /// identifier /// typespec /// typequal /// storageclass /// /// FIXME: The GCC grammar/code for this construct implies we need two /// token lookahead. Comment from gcc: "If they start with an identifier /// which is followed by a comma or close parenthesis, then the arguments /// start with that identifier; otherwise they are an expression list." /// /// GCC does not require the ',' between attribs in an attribute-list. /// /// At the moment, I am not doing 2 token lookahead. I am also unaware of /// any attributes that don't work (based on my limited testing). Most /// attributes are very simple in practice. Until we find a bug, I don't see /// a pressing need to implement the 2 token lookahead. void Parser::ParseGNUAttributes(ParsedAttributes &attrs, SourceLocation *endLoc, LateParsedAttrList *LateAttrs) { assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); while (Tok.is(tok::kw___attribute)) { ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "attribute")) { SkipUntil(tok::r_paren, true); // skip until ) or ; return; } if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) { SkipUntil(tok::r_paren, true); // skip until ) or ; return; } // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) while (Tok.is(tok::identifier) || isDeclarationSpecifier() || Tok.is(tok::comma)) { if (Tok.is(tok::comma)) { // allows for empty/non-empty attributes. ((__vector_size__(16),,,,)) ConsumeToken(); continue; } // we have an identifier or declaration specifier (const, int, etc.) IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.is(tok::l_paren)) { // handle "parameterized" attributes if (LateAttrs && isAttributeLateParsed(*AttrName)) { LateParsedAttribute *LA = new LateParsedAttribute(this, *AttrName, AttrNameLoc); LateAttrs->push_back(LA); // Attributes in a class are parsed at the end of the class, along // with other late-parsed declarations. if (!ClassStack.empty()) getCurrentClass().LateParsedDeclarations.push_back(LA); // consume everything up to and including the matching right parens ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false); Token Eof; Eof.startToken(); Eof.setLocation(Tok.getLocation()); LA->Toks.push_back(Eof); } else { ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc); } } else { attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); SourceLocation Loc = Tok.getLocation(); if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { SkipUntil(tok::r_paren, false); } if (endLoc) *endLoc = Loc; } } /// Parse the arguments to a parameterized GNU attribute void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc) { assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); // Availability attributes have their own grammar. if (AttrName->isStr("availability")) { ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } // Thread safety attributes fit into the FIXME case above, so we // just parse the arguments as a list of expressions if (IsThreadSafetyAttribute(AttrName->getName())) { ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } ConsumeParen(); // ignore the left paren loc for now IdentifierInfo *ParmName = 0; SourceLocation ParmLoc; bool BuiltinType = false; switch (Tok.getKind()) { case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_bool: case tok::kw_short: case tok::kw_int: case tok::kw_long: case tok::kw___int64: case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_float: case tok::kw_double: case tok::kw_void: case tok::kw_typeof: // __attribute__(( vec_type_hint(char) )) // FIXME: Don't just discard the builtin type token. ConsumeToken(); BuiltinType = true; break; case tok::identifier: ParmName = Tok.getIdentifierInfo(); ParmLoc = ConsumeToken(); break; default: break; } ExprVector ArgExprs(Actions); if (!BuiltinType && (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) { // Eat the comma. if (ParmLoc.isValid()) ConsumeToken(); // Parse the non-empty comma-separated list of expressions. while (1) { ExprResult ArgExpr(ParseAssignmentExpression()); if (ArgExpr.isInvalid()) { SkipUntil(tok::r_paren); return; } ArgExprs.push_back(ArgExpr.release()); if (Tok.isNot(tok::comma)) break; ConsumeToken(); // Eat the comma, move to the next argument } } else if (Tok.is(tok::less) && AttrName->isStr("iboutletcollection")) { if (!ExpectAndConsume(tok::less, diag::err_expected_less_after, "<", tok::greater)) { while (Tok.is(tok::identifier)) { ConsumeToken(); if (Tok.is(tok::greater)) break; if (Tok.is(tok::comma)) { ConsumeToken(); continue; } } if (Tok.isNot(tok::greater)) Diag(Tok, diag::err_iboutletcollection_with_protocol); SkipUntil(tok::r_paren, false, true); // skip until ')' } } SourceLocation RParen = Tok.getLocation(); if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { AttributeList *attr = Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); if (BuiltinType && attr->getKind() == AttributeList::AT_iboutletcollection) Diag(Tok, diag::err_iboutletcollection_builtintype); } } /// ParseMicrosoftDeclSpec - Parse an __declspec construct /// /// [MS] decl-specifier: /// __declspec ( extended-decl-modifier-seq ) /// /// [MS] extended-decl-modifier-seq: /// extended-decl-modifier[opt] /// extended-decl-modifier extended-decl-modifier-seq void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { assert(Tok.is(tok::kw___declspec) && "Not a declspec!"); ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "declspec")) { SkipUntil(tok::r_paren, true); // skip until ) or ; return; } while (Tok.getIdentifierInfo()) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); // FIXME: Remove this when we have proper __declspec(property()) support. // Just skip everything inside property(). if (AttrName->getName() == "property") { ConsumeParen(); SkipUntil(tok::r_paren); } if (Tok.is(tok::l_paren)) { ConsumeParen(); // FIXME: This doesn't parse __declspec(property(get=get_func_name)) // correctly. ExprResult ArgExpr(ParseAssignmentExpression()); if (!ArgExpr.isInvalid()) { Expr *ExprList = ArgExpr.take(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), &ExprList, 1, true); } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); } else { attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, true); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); return; } void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { // Treat these like attributes // FIXME: Allow Sema to distinguish between these and real attributes! while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr32)) // FIXME: Support these properly! continue; attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, true); } } void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { // Treat these like attributes while (Tok.is(tok::kw___pascal)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, true); } } void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { // Treat these like attributes while (Tok.is(tok::kw___kernel)) { SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"), AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, false); } } void Parser::ParseOpenCLQualifiers(DeclSpec &DS) { SourceLocation Loc = Tok.getLocation(); switch(Tok.getKind()) { // OpenCL qualifiers: case tok::kw___private: case tok::kw_private: DS.getAttributes().addNewInteger( Actions.getASTContext(), PP.getIdentifierInfo("address_space"), Loc, 0); break; case tok::kw___global: DS.getAttributes().addNewInteger( Actions.getASTContext(), PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_global); break; case tok::kw___local: DS.getAttributes().addNewInteger( Actions.getASTContext(), PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_local); break; case tok::kw___constant: DS.getAttributes().addNewInteger( Actions.getASTContext(), PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_constant); break; case tok::kw___read_only: DS.getAttributes().addNewInteger( Actions.getASTContext(), PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_only); break; case tok::kw___write_only: DS.getAttributes().addNewInteger( Actions.getASTContext(), PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_write_only); break; case tok::kw___read_write: DS.getAttributes().addNewInteger( Actions.getASTContext(), PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_write); break; default: break; } } /// \brief Parse a version number. /// /// version: /// simple-integer /// simple-integer ',' simple-integer /// simple-integer ',' simple-integer ',' simple-integer VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { Range = Tok.getLocation(); if (!Tok.is(tok::numeric_constant)) { Diag(Tok, diag::err_expected_version); SkipUntil(tok::comma, tok::r_paren, true, true, true); return VersionTuple(); } // Parse the major (and possibly minor and subminor) versions, which // are stored in the numeric constant. We utilize a quirk of the // lexer, which is that it handles something like 1.2.3 as a single // numeric constant, rather than two separate tokens. SmallString<512> Buffer; Buffer.resize(Tok.getLength()+1); const char *ThisTokBegin = &Buffer[0]; // Get the spelling of the token, which eliminates trigraphs, etc. bool Invalid = false; unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid); if (Invalid) return VersionTuple(); // Parse the major version. unsigned AfterMajor = 0; unsigned Major = 0; while (AfterMajor < ActualLength && isdigit(ThisTokBegin[AfterMajor])) { Major = Major * 10 + ThisTokBegin[AfterMajor] - '0'; ++AfterMajor; } if (AfterMajor == 0) { Diag(Tok, diag::err_expected_version); SkipUntil(tok::comma, tok::r_paren, true, true, true); return VersionTuple(); } if (AfterMajor == ActualLength) { ConsumeToken(); // We only had a single version component. if (Major == 0) { Diag(Tok, diag::err_zero_version); return VersionTuple(); } return VersionTuple(Major); } if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) { Diag(Tok, diag::err_expected_version); SkipUntil(tok::comma, tok::r_paren, true, true, true); return VersionTuple(); } // Parse the minor version. unsigned AfterMinor = AfterMajor + 1; unsigned Minor = 0; while (AfterMinor < ActualLength && isdigit(ThisTokBegin[AfterMinor])) { Minor = Minor * 10 + ThisTokBegin[AfterMinor] - '0'; ++AfterMinor; } if (AfterMinor == ActualLength) { ConsumeToken(); // We had major.minor. if (Major == 0 && Minor == 0) { Diag(Tok, diag::err_zero_version); return VersionTuple(); } return VersionTuple(Major, Minor); } // If what follows is not a '.', we have a problem. if (ThisTokBegin[AfterMinor] != '.') { Diag(Tok, diag::err_expected_version); SkipUntil(tok::comma, tok::r_paren, true, true, true); return VersionTuple(); } // Parse the subminor version. unsigned AfterSubminor = AfterMinor + 1; unsigned Subminor = 0; while (AfterSubminor < ActualLength && isdigit(ThisTokBegin[AfterSubminor])) { Subminor = Subminor * 10 + ThisTokBegin[AfterSubminor] - '0'; ++AfterSubminor; } if (AfterSubminor != ActualLength) { Diag(Tok, diag::err_expected_version); SkipUntil(tok::comma, tok::r_paren, true, true, true); return VersionTuple(); } ConsumeToken(); return VersionTuple(Major, Minor, Subminor); } /// \brief Parse the contents of the "availability" attribute. /// /// availability-attribute: /// 'availability' '(' platform ',' version-arg-list, opt-message')' /// /// platform: /// identifier /// /// version-arg-list: /// version-arg /// version-arg ',' version-arg-list /// /// version-arg: /// 'introduced' '=' version /// 'deprecated' '=' version /// 'obsoleted' = version /// 'unavailable' /// opt-message: /// 'message' '=' void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, SourceLocation AvailabilityLoc, ParsedAttributes &attrs, SourceLocation *endLoc) { SourceLocation PlatformLoc; IdentifierInfo *Platform = 0; enum { Introduced, Deprecated, Obsoleted, Unknown }; AvailabilityChange Changes[Unknown]; ExprResult MessageExpr; // Opening '('. BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen); return; } // Parse the platform name, if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_availability_expected_platform); SkipUntil(tok::r_paren); return; } Platform = Tok.getIdentifierInfo(); PlatformLoc = ConsumeToken(); // Parse the ',' following the platform name. if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren)) return; // If we haven't grabbed the pointers for the identifiers // "introduced", "deprecated", and "obsoleted", do so now. if (!Ident_introduced) { Ident_introduced = PP.getIdentifierInfo("introduced"); Ident_deprecated = PP.getIdentifierInfo("deprecated"); Ident_obsoleted = PP.getIdentifierInfo("obsoleted"); Ident_unavailable = PP.getIdentifierInfo("unavailable"); Ident_message = PP.getIdentifierInfo("message"); } // Parse the set of introductions/deprecations/removals. SourceLocation UnavailableLoc; do { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_availability_expected_change); SkipUntil(tok::r_paren); return; } IdentifierInfo *Keyword = Tok.getIdentifierInfo(); SourceLocation KeywordLoc = ConsumeToken(); if (Keyword == Ident_unavailable) { if (UnavailableLoc.isValid()) { Diag(KeywordLoc, diag::err_availability_redundant) << Keyword << SourceRange(UnavailableLoc); } UnavailableLoc = KeywordLoc; if (Tok.isNot(tok::comma)) break; ConsumeToken(); continue; } if (Tok.isNot(tok::equal)) { Diag(Tok, diag::err_expected_equal_after) << Keyword; SkipUntil(tok::r_paren); return; } ConsumeToken(); if (Keyword == Ident_message) { if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal); SkipUntil(tok::r_paren); return; } MessageExpr = ParseStringLiteralExpression(); break; } SourceRange VersionRange; VersionTuple Version = ParseVersionTuple(VersionRange); if (Version.empty()) { SkipUntil(tok::r_paren); return; } unsigned Index; if (Keyword == Ident_introduced) Index = Introduced; else if (Keyword == Ident_deprecated) Index = Deprecated; else if (Keyword == Ident_obsoleted) Index = Obsoleted; else Index = Unknown; if (Index < Unknown) { if (!Changes[Index].KeywordLoc.isInvalid()) { Diag(KeywordLoc, diag::err_availability_redundant) << Keyword << SourceRange(Changes[Index].KeywordLoc, Changes[Index].VersionRange.getEnd()); } Changes[Index].KeywordLoc = KeywordLoc; Changes[Index].Version = Version; Changes[Index].VersionRange = VersionRange; } else { Diag(KeywordLoc, diag::err_availability_unknown_change) << Keyword << VersionRange; } if (Tok.isNot(tok::comma)) break; ConsumeToken(); } while (true); // Closing ')'. if (T.consumeClose()) return; if (endLoc) *endLoc = T.getCloseLocation(); // The 'unavailable' availability cannot be combined with any other // availability changes. Make sure that hasn't happened. if (UnavailableLoc.isValid()) { bool Complained = false; for (unsigned Index = Introduced; Index != Unknown; ++Index) { if (Changes[Index].KeywordLoc.isValid()) { if (!Complained) { Diag(UnavailableLoc, diag::warn_availability_and_unavailable) << SourceRange(Changes[Index].KeywordLoc, Changes[Index].VersionRange.getEnd()); Complained = true; } // Clear out the availability. Changes[Index] = AvailabilityChange(); } } } // Record this attribute attrs.addNew(&Availability, SourceRange(AvailabilityLoc, T.getCloseLocation()), 0, AvailabilityLoc, Platform, PlatformLoc, Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], UnavailableLoc, MessageExpr.take(), false, false); } // Late Parsed Attributes: // See other examples of late parsing in lib/Parse/ParseCXXInlineMethods void Parser::LateParsedDeclaration::ParseLexedAttributes() {} void Parser::LateParsedClass::ParseLexedAttributes() { Self->ParseLexedAttributes(*Class); } void Parser::LateParsedAttribute::ParseLexedAttributes() { Self->ParseLexedAttribute(*this, true, false); } /// Wrapper class which calls ParseLexedAttribute, after setting up the /// scope appropriately. void Parser::ParseLexedAttributes(ParsingClass &Class) { // Deal with templates // FIXME: Test cases to make sure this does the right thing for templates. bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); // Set or update the scope flags. bool AlreadyHasClassScope = Class.TopLevelClass; unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); // Enter the scope of nested classes if (!AlreadyHasClassScope) Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); { // Allow 'this' within late-parsed attributes. Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, /*TypeQuals=*/0); for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){ Class.LateParsedDeclarations[i]->ParseLexedAttributes(); } } if (!AlreadyHasClassScope) Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); } /// \brief Parse all attributes in LAs, and attach them to Decl D. void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, bool EnterScope, bool OnDefinition) { for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) { LAs[i]->addDecl(D); ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition); delete LAs[i]; } LAs.clear(); } /// \brief Finish parsing an attribute for which parsing was delayed. /// This will be called at the end of parsing a class declaration /// for each LateParsedAttribute. We consume the saved tokens and /// create an attribute with the arguments filled in. We add this /// to the Attribute list for the decl. void Parser::ParseLexedAttribute(LateParsedAttribute &LA, bool EnterScope, bool OnDefinition) { // Save the current token position. SourceLocation OrigLoc = Tok.getLocation(); // Append the current token at the end of the new token stream so that it // doesn't get lost. LA.Toks.push_back(Tok); PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false); // Consume the previously pushed token. ConsumeAnyToken(); if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) { Diag(Tok, diag::warn_attribute_on_function_definition) << LA.AttrName.getName(); } ParsedAttributes Attrs(AttrFactory); SourceLocation endLoc; if (LA.Decls.size() == 1) { Decl *D = LA.Decls[0]; // If the Decl is templatized, add template parameters to scope. bool HasTemplateScope = EnterScope && D->isTemplateDecl(); ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope); if (HasTemplateScope) Actions.ActOnReenterTemplateScope(Actions.CurScope, D); // If the Decl is on a function, add function parameters to the scope. bool HasFunctionScope = EnterScope && D->isFunctionOrFunctionTemplate(); ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope); if (HasFunctionScope) Actions.ActOnReenterFunctionContext(Actions.CurScope, D); ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); if (HasFunctionScope) { Actions.ActOnExitFunctionContext(); FnScope.Exit(); // Pop scope, and remove Decls from IdResolver } if (HasTemplateScope) { TempScope.Exit(); } } else if (LA.Decls.size() > 0) { // If there are multiple decls, then the decl cannot be within the // function scope. ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); } else { Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName(); } for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i) { Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs); } if (Tok.getLocation() != OrigLoc) { // Due to a parsing error, we either went over the cached tokens or // there are still cached tokens left, so we skip the leftover tokens. // Since this is an uncommon situation that should be avoided, use the // expensive isBeforeInTranslationUnit call. if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), OrigLoc)) while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); } } /// \brief Wrapper around a case statement checking if AttrName is /// one of the thread safety attributes bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){ return llvm::StringSwitch(AttrName) .Case("guarded_by", true) .Case("guarded_var", true) .Case("pt_guarded_by", true) .Case("pt_guarded_var", true) .Case("lockable", true) .Case("scoped_lockable", true) .Case("no_thread_safety_analysis", true) .Case("acquired_after", true) .Case("acquired_before", true) .Case("exclusive_lock_function", true) .Case("shared_lock_function", true) .Case("exclusive_trylock_function", true) .Case("shared_trylock_function", true) .Case("unlock_function", true) .Case("lock_returned", true) .Case("locks_excluded", true) .Case("exclusive_locks_required", true) .Case("shared_locks_required", true) .Default(false); } /// \brief Parse the contents of thread safety attributes. These /// should always be parsed as an expression list. /// /// We need to special case the parsing due to the fact that if the first token /// of the first argument is an identifier, the main parse loop will store /// that token as a "parameter" and the rest of /// the arguments will be added to a list of "arguments". However, /// subsequent tokens in the first argument are lost. We instead parse each /// argument as an expression and add all arguments to the list of "arguments". /// In future, we will take advantage of this special case to also /// deal with some argument scoping issues here (for example, referring to a /// function parameter in the attribute on that function). void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc) { assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ExprVector ArgExprs(Actions); bool ArgExprsOk = true; // now parse the list of expressions while (Tok.isNot(tok::r_paren)) { ExprResult ArgExpr(ParseAssignmentExpression()); if (ArgExpr.isInvalid()) { ArgExprsOk = false; T.consumeClose(); break; } else { ArgExprs.push_back(ArgExpr.release()); } if (Tok.isNot(tok::comma)) break; ConsumeToken(); // Eat the comma, move to the next argument } // Match the ')'. if (ArgExprsOk && !T.consumeClose()) { Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), ArgExprs.take(), ArgExprs.size()); } if (EndLoc) *EndLoc = T.getCloseLocation(); } /// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets /// of a C++11 attribute-specifier in a location where an attribute is not /// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this /// situation. /// /// \return \c true if we skipped an attribute-like chunk of tokens, \c false if /// this doesn't appear to actually be an attribute-specifier, and the caller /// should try to parse it. bool Parser::DiagnoseProhibitedCXX11Attribute() { assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)); switch (isCXX11AttributeSpecifier(/*Disambiguate*/true)) { case CAK_NotAttributeSpecifier: // No diagnostic: we're in Obj-C++11 and this is not actually an attribute. return false; case CAK_InvalidAttributeSpecifier: Diag(Tok.getLocation(), diag::err_l_square_l_square_not_attribute); return false; case CAK_AttributeSpecifier: // Parse and discard the attributes. SourceLocation BeginLoc = ConsumeBracket(); ConsumeBracket(); SkipUntil(tok::r_square, /*StopAtSemi*/ false); assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied"); SourceLocation EndLoc = ConsumeBracket(); Diag(BeginLoc, diag::err_attributes_not_allowed) << SourceRange(BeginLoc, EndLoc); return true; } llvm_unreachable("All cases handled above."); } void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) << attrs.Range; } /// ParseDeclaration - Parse a full 'declaration', which consists of /// declaration-specifiers, some number of declarators, and a semicolon. /// 'Context' should be a Declarator::TheContext value. This returns the /// location of the semicolon in DeclEnd. /// /// declaration: [C99 6.7] /// block-declaration -> /// simple-declaration /// others [FIXME] /// [C++] template-declaration /// [C++] namespace-definition /// [C++] using-directive /// [C++] using-declaration /// [C++11/C11] static_assert-declaration /// others... [FIXME] /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, unsigned Context, SourceLocation &DeclEnd, ParsedAttributesWithRange &attrs) { ParenBraceBracketBalancer BalancerRAIIObj(*this); // Must temporarily exit the objective-c container scope for // parsing c none objective-c decls. ObjCDeclContextSwitch ObjCDC(*this); Decl *SingleDecl = 0; Decl *OwnedType = 0; switch (Tok.getKind()) { case tok::kw_template: case tok::kw_export: ProhibitAttributes(attrs); SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd); break; case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) { ProhibitAttributes(attrs); SourceLocation InlineLoc = ConsumeToken(); SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc); break; } return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, true); case tok::kw_namespace: ProhibitAttributes(attrs); SingleDecl = ParseNamespace(Context, DeclEnd); break; case tok::kw_using: SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(), DeclEnd, attrs, &OwnedType); break; case tok::kw_static_assert: case tok::kw__Static_assert: ProhibitAttributes(attrs); SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, true); } // This routine returns a DeclGroup, if the thing we parsed only contains a // single decl, convert it now. Alias declarations can also declare a type; // include that too if it is present. return Actions.ConvertDeclToDeclGroup(SingleDecl, OwnedType); } /// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl] /// declaration-specifiers init-declarator-list[opt] ';' ///[C90/C++]init-declarator-list ';' [TODO] /// [OMP] threadprivate-directive [TODO] /// /// for-range-declaration: [C++0x 6.5p1: stmt.ranged] /// attribute-specifier-seq[opt] type-specifier-seq declarator /// /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. If it is true, it checks for and eats it. /// /// If FRI is non-null, we might be parsing a for-range-declaration instead /// of a simple-declaration. If we find that we are, we also parse the /// for-range-initializer, and place it here. Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context, SourceLocation &DeclEnd, ParsedAttributes &attrs, bool RequireSemi, ForRangeInit *FRI) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); DS.takeAttributesFrom(attrs); ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, getDeclSpecContextFromDeclaratorContext(Context)); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { if (RequireSemi) ConsumeToken(); Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); } /// Returns true if this might be the start of a declarator, or a common typo /// for a declarator. bool Parser::MightBeDeclarator(unsigned Context) { switch (Tok.getKind()) { case tok::annot_cxxscope: case tok::annot_template_id: case tok::caret: case tok::code_completion: case tok::coloncolon: case tok::ellipsis: case tok::kw___attribute: case tok::kw_operator: case tok::l_paren: case tok::star: return true; case tok::amp: case tok::ampamp: return getLangOpts().CPlusPlus; case tok::l_square: // Might be an attribute on an unnamed bit-field. return Context == Declarator::MemberContext && getLangOpts().CPlusPlus0x && NextToken().is(tok::l_square); case tok::colon: // Might be a typo for '::' or an unnamed bit-field. return Context == Declarator::MemberContext || getLangOpts().CPlusPlus; case tok::identifier: switch (NextToken().getKind()) { case tok::code_completion: case tok::coloncolon: case tok::comma: case tok::equal: case tok::equalequal: // Might be a typo for '='. case tok::kw_alignas: case tok::kw_asm: case tok::kw___attribute: case tok::l_brace: case tok::l_paren: case tok::l_square: case tok::less: case tok::r_brace: case tok::r_paren: case tok::r_square: case tok::semi: return true; case tok::colon: // At namespace scope, 'identifier:' is probably a typo for 'identifier::' // and in block scope it's probably a label. Inside a class definition, // this is a bit-field. return Context == Declarator::MemberContext || (getLangOpts().CPlusPlus && Context == Declarator::FileContext); case tok::identifier: // Possible virt-specifier. return getLangOpts().CPlusPlus0x && isCXX0XVirtSpecifier(NextToken()); default: return false; } default: return false; } } /// Skip until we reach something which seems like a sensible place to pick /// up parsing after a malformed declaration. This will sometimes stop sooner /// than SkipUntil(tok::r_brace) would, but will never stop later. void Parser::SkipMalformedDecl() { while (true) { switch (Tok.getKind()) { case tok::l_brace: // Skip until matching }, then stop. We've probably skipped over // a malformed class or function definition or similar. ConsumeBrace(); SkipUntil(tok::r_brace, /*StopAtSemi*/false); if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) { // This declaration isn't over yet. Keep skipping. continue; } if (Tok.is(tok::semi)) ConsumeToken(); return; case tok::l_square: ConsumeBracket(); SkipUntil(tok::r_square, /*StopAtSemi*/false); continue; case tok::l_paren: ConsumeParen(); SkipUntil(tok::r_paren, /*StopAtSemi*/false); continue; case tok::r_brace: return; case tok::semi: ConsumeToken(); return; case tok::kw_inline: // 'inline namespace' at the start of a line is almost certainly // a good place to pick back up parsing. if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace)) return; break; case tok::kw_namespace: // 'namespace' at the start of a line is almost certainly a good // place to pick back up parsing. if (Tok.isAtStartOfLine()) return; break; case tok::eof: return; default: break; } ConsumeAnyToken(); } } /// ParseDeclGroup - Having concluded that this is either a function /// definition or a group of object declarations, actually parse the /// result. Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, bool AllowFunctionDefinitions, SourceLocation *DeclEnd, ForRangeInit *FRI) { // Parse the first declarator. ParsingDeclarator D(*this, DS, static_cast(Context)); ParseDeclarator(D); // Bail out if the first declarator didn't seem well-formed. if (!D.hasName() && !D.mayOmitIdentifier()) { SkipMalformedDecl(); return DeclGroupPtrTy(); } // Save late-parsed attributes for now; they need to be parsed in the // appropriate function scope after the function Decl has been constructed. LateParsedAttrList LateParsedAttrs; if (D.isFunctionDeclarator()) MaybeParseGNUAttributes(D, &LateParsedAttrs); // Check to see if we have a function *definition* which must have a body. if (AllowFunctionDefinitions && D.isFunctionDeclarator() && // Look at the next token to make sure that this isn't a function // declaration. We have to check this because __attribute__ might be the // start of a function definition in GCC-extended K&R C. !isDeclarationAfterDeclarator()) { if (isStartOfFunctionDefinition(D)) { if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { Diag(Tok, diag::err_function_declared_typedef); // Recover by treating the 'typedef' as spurious. DS.ClearStorageClassSpecs(); } Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); return Actions.ConvertDeclToDeclGroup(TheDecl); } if (isDeclarationSpecifier()) { // If there is an invalid declaration specifier right after the function // prototype, then we must be in a missing semicolon case where this isn't // actually a body. Just fall through into the code that handles it as a // prototype, and let the top-level code handle the erroneous declspec // where it would otherwise expect a comma or semicolon. } else { Diag(Tok, diag::err_expected_fn_body); SkipUntil(tok::semi); return DeclGroupPtrTy(); } } if (ParseAsmAttributesAfterDeclarator(D)) return DeclGroupPtrTy(); // C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we // must parse and analyze the for-range-initializer before the declaration is // analyzed. if (FRI && Tok.is(tok::colon)) { FRI->ColonLoc = ConsumeToken(); if (Tok.is(tok::l_brace)) FRI->RangeExpr = ParseBraceInitializer(); else FRI->RangeExpr = ParseExpression(); Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); Actions.ActOnCXXForRangeDecl(ThisDecl); Actions.FinalizeDeclaration(ThisDecl); D.complete(ThisDecl); return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); } SmallVector DeclsInGroup; Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D); if (LateParsedAttrs.size() > 0) ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false); D.complete(FirstDecl); if (FirstDecl) DeclsInGroup.push_back(FirstDecl); bool ExpectSemi = Context != Declarator::ForContext; // If we don't have a comma, it is either the end of the list (a ';') or an // error, bail out. while (Tok.is(tok::comma)) { SourceLocation CommaLoc = ConsumeToken(); if (Tok.isAtStartOfLine() && ExpectSemi && !MightBeDeclarator(Context)) { // This comma was followed by a line-break and something which can't be // the start of a declarator. The comma was probably a typo for a // semicolon. Diag(CommaLoc, diag::err_expected_semi_declaration) << FixItHint::CreateReplacement(CommaLoc, ";"); ExpectSemi = false; break; } // Parse the next declarator. D.clear(); D.setCommaLoc(CommaLoc); // Accept attributes in an init-declarator. In the first declarator in a // declaration, these would be part of the declspec. In subsequent // declarators, they become part of the declarator itself, so that they // don't apply to declarators after *this* one. Examples: // short __attribute__((common)) var; -> declspec // short var __attribute__((common)); -> declarator // short x, __attribute__((common)) var; -> declarator MaybeParseGNUAttributes(D); ParseDeclarator(D); if (!D.isInvalidType()) { Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); D.complete(ThisDecl); if (ThisDecl) DeclsInGroup.push_back(ThisDecl); } } if (DeclEnd) *DeclEnd = Tok.getLocation(); if (ExpectSemi && ExpectAndConsume(tok::semi, Context == Declarator::FileContext ? diag::err_invalid_token_after_toplevel_declarator : diag::err_expected_semi_declaration)) { // Okay, there was no semicolon and one was expected. If we see a // declaration specifier, just assume it was missing and continue parsing. // Otherwise things are very confused and we skip to recover. if (!isDeclarationSpecifier()) { SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) ConsumeToken(); } } return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup.data(), DeclsInGroup.size()); } /// Parse an optional simple-asm-expr and attributes, and attach them to a /// declarator. Returns true on an error. bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi, true, true); return true; } D.setAsmLabel(AsmLabel.release()); D.SetRangeEnd(Loc); } MaybeParseGNUAttributes(D); return false; } /// \brief Parse 'declaration' after parsing 'declaration-specifiers /// declarator'. This method parses the remainder of the declaration /// (including any attributes or initializer, among other things) and /// finalizes the declaration. /// /// init-declarator: [C99 6.7] /// declarator /// declarator '=' initializer /// [GNU] declarator simple-asm-expr[opt] attributes[opt] /// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer /// [C++] declarator initializer[opt] /// /// [C++] initializer: /// [C++] '=' initializer-clause /// [C++] '(' expression-list ')' /// [C++0x] '=' 'default' [TODO] /// [C++0x] '=' 'delete' /// [C++0x] braced-init-list /// /// According to the standard grammar, =default and =delete are function /// definitions, but that definitely doesn't fit with the parser here. /// Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo) { if (ParseAsmAttributesAfterDeclarator(D)) return 0; return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo); } Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, const ParsedTemplateInfo &TemplateInfo) { // Inform the current actions module that we just parsed this declarator. Decl *ThisDecl = 0; switch (TemplateInfo.Kind) { case ParsedTemplateInfo::NonTemplate: ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); break; case ParsedTemplateInfo::Template: case ParsedTemplateInfo::ExplicitSpecialization: ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), MultiTemplateParamsArg(Actions, TemplateInfo.TemplateParams->data(), TemplateInfo.TemplateParams->size()), D); break; case ParsedTemplateInfo::ExplicitInstantiation: { DeclResult ThisRes = Actions.ActOnExplicitInstantiation(getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D); if (ThisRes.isInvalid()) { SkipUntil(tok::semi, true, true); return 0; } ThisDecl = ThisRes.get(); break; } } bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; // Parse declarator '=' initializer. // If a '==' or '+=' is found, suggest a fixit to '='. if (isTokenEqualOrEqualTypo()) { ConsumeToken(); if (Tok.is(tok::kw_delete)) { if (D.isFunctionDeclarator()) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) << 1 /* delete */; else Diag(ConsumeToken(), diag::err_deleted_non_function); } else if (Tok.is(tok::kw_default)) { if (D.isFunctionDeclarator()) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) << 0 /* default */; else Diag(ConsumeToken(), diag::err_default_special_members); } else { if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { EnterScope(0); Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); } if (Tok.is(tok::code_completion)) { Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); cutOffParsing(); return 0; } ExprResult Init(ParseInitializer()); if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); ExitScope(); } if (Init.isInvalid()) { SkipUntil(tok::comma, true, true); Actions.ActOnInitializerError(ThisDecl); } else Actions.AddInitializerToDecl(ThisDecl, Init.take(), /*DirectInit=*/false, TypeContainsAuto); } } else if (Tok.is(tok::l_paren)) { // Parse C++ direct initializer: '(' expression-list ')' BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ExprVector Exprs(Actions); CommaLocsTy CommaLocs; if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { EnterScope(0); Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); } if (ParseExpressionList(Exprs, CommaLocs)) { SkipUntil(tok::r_paren); if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); ExitScope(); } } else { // Match the ')'. T.consumeClose(); assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && "Unexpected number of commas!"); if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); ExitScope(); } ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), T.getCloseLocation(), move_arg(Exprs)); Actions.AddInitializerToDecl(ThisDecl, Initializer.take(), /*DirectInit=*/true, TypeContainsAuto); } } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { // Parse C++0x braced-init-list. Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); if (D.getCXXScopeSpec().isSet()) { EnterScope(0); Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); } ExprResult Init(ParseBraceInitializer()); if (D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); ExitScope(); } if (Init.isInvalid()) { Actions.ActOnInitializerError(ThisDecl); } else Actions.AddInitializerToDecl(ThisDecl, Init.take(), /*DirectInit=*/true, TypeContainsAuto); } else { Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto); } Actions.FinalizeDeclaration(ThisDecl); return ThisDecl; } /// ParseSpecifierQualifierList /// specifier-qualifier-list: /// type-specifier specifier-qualifier-list[opt] /// type-qualifier specifier-qualifier-list[opt] /// [GNU] attributes specifier-qualifier-list[opt] /// void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSC) { /// specifier-qualifier-list is a subset of declaration-specifiers. Just /// parse declaration-specifiers and complain about extra stuff. /// TODO: diagnose attribute-specifiers and alignment-specifiers. ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC); // Validate declspec for type-name. unsigned Specs = DS.getParsedSpecifiers(); if (DSC == DSC_type_specifier && !DS.hasTypeSpecifier()) { Diag(Tok, diag::err_expected_type); DS.SetTypeSpecError(); } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && !DS.hasAttributes()) { Diag(Tok, diag::err_typename_requires_specqual); if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); } // Issue diagnostic and remove storage class if present. if (Specs & DeclSpec::PQ_StorageClassSpecifier) { if (DS.getStorageClassSpecLoc().isValid()) Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass); else Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass); DS.ClearStorageClassSpecs(); } // Issue diagnostic and remove function specfier if present. if (Specs & DeclSpec::PQ_FunctionSpecifier) { if (DS.isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec); if (DS.isVirtualSpecified()) Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec); if (DS.isExplicitSpecified()) Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec); DS.ClearFunctionSpecs(); } // Issue diagnostic and remove constexpr specfier if present. if (DS.isConstexprSpecified()) { Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr); DS.ClearConstexprSpec(); } } /// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the /// specified token is valid after the identifier in a declarator which /// immediately follows the declspec. For example, these things are valid: /// /// int x [ 4]; // direct-declarator /// int x ( int y); // direct-declarator /// int(int x ) // direct-declarator /// int x ; // simple-declaration /// int x = 17; // init-declarator-list /// int x , y; // init-declarator-list /// int x __asm__ ("foo"); // init-declarator-list /// int x : 4; // struct-declarator /// int x { 5}; // C++'0x unified initializers /// /// This is not, because 'x' does not immediately follow the declspec (though /// ')' happens to be valid anyway). /// int (x) /// static bool isValidAfterIdentifierInDeclarator(const Token &T) { return T.is(tok::l_square) || T.is(tok::l_paren) || T.is(tok::r_paren) || T.is(tok::semi) || T.is(tok::comma) || T.is(tok::equal) || T.is(tok::kw_asm) || T.is(tok::l_brace) || T.is(tok::colon); } /// ParseImplicitInt - This method is called when we have an non-typename /// identifier in a declspec (which normally terminates the decl spec) when /// the declspec has no type specifier. In this case, the declspec is either /// malformed or is "implicit int" (in K&R and C89). /// /// This method handles diagnosing this prettily and returns false if the /// declspec is done being processed. If it recovers and thinks there may be /// other pieces of declspec after it, it returns true. /// bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC) { assert(Tok.is(tok::identifier) && "should have identifier"); SourceLocation Loc = Tok.getLocation(); // If we see an identifier that is not a type name, we normally would // parse it as the identifer being declared. However, when a typename // is typo'd or the definition is not included, this will incorrectly // parse the typename as the identifier name and fall over misparsing // later parts of the diagnostic. // // As such, we try to do some look-ahead in cases where this would // otherwise be an "implicit-int" case to see if this is invalid. For // example: "static foo_t x = 4;" In this case, if we parsed foo_t as // an identifier with implicit int, we'd get a parse error because the // next token is obviously invalid for a type. Parse these as a case // with an invalid type specifier. assert(!DS.hasTypeSpecifier() && "Type specifier checked above"); // Since we know that this either implicit int (which is rare) or an // error, do lookahead to try to do better recovery. This never applies within // a type specifier. // FIXME: Don't bail out here in languages with no implicit int (like // C++ with no -fms-extensions). This is much more likely to be an undeclared // type or typo than a use of implicit int. if (DSC != DSC_type_specifier && isValidAfterIdentifierInDeclarator(NextToken())) { // If this token is valid for implicit int, e.g. "static x = 4", then // we just avoid eating the identifier, so it will be parsed as the // identifier in the declarator. return false; } // Otherwise, if we don't consume this token, we are going to emit an // error anyway. Try to recover from various common problems. Check // to see if this was a reference to a tag name without a tag specified. // This is a common problem in C (saying 'foo' instead of 'struct foo'). // // C++ doesn't need this, and isTagName doesn't take SS. if (SS == 0) { const char *TagName = 0, *FixitTagName = 0; tok::TokenKind TagKind = tok::unknown; switch (Actions.isTagName(*Tok.getIdentifierInfo(), getCurScope())) { default: break; case DeclSpec::TST_enum: TagName="enum" ; FixitTagName = "enum " ; TagKind=tok::kw_enum ;break; case DeclSpec::TST_union: TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union ;break; case DeclSpec::TST_struct: TagName="struct"; FixitTagName = "struct ";TagKind=tok::kw_struct;break; case DeclSpec::TST_class: TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break; } if (TagName) { Diag(Loc, diag::err_use_of_tag_name_without_tag) << Tok.getIdentifierInfo() << TagName << getLangOpts().CPlusPlus << FixItHint::CreateInsertion(Tok.getLocation(),FixitTagName); // Parse this as a tag as if the missing tag were present. if (TagKind == tok::kw_enum) ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSC_normal); else ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS, /*EnteringContext*/ false, DSC_normal); return true; } } // This is almost certainly an invalid type name. Let the action emit a // diagnostic and attempt to recover. ParsedType T; if (Actions.DiagnoseUnknownTypeName(*Tok.getIdentifierInfo(), Loc, getCurScope(), SS, T)) { // The action emitted a diagnostic, so we don't have to. if (T) { // The action has suggested that the type T could be used. Set that as // the type in the declaration specifiers, consume the would-be type // name token, and we're done. const char *PrevSpec; unsigned DiagID; DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T); DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // There may be other declaration specifiers after this. return true; } // Fall through; the action had no suggestion for us. } else { // The action did not emit a diagnostic, so emit one now. SourceRange R; if (SS) R = SS->getRange(); Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R; } // Mark this as an error. DS.SetTypeSpecError(); DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // TODO: Could inject an invalid typedef decl in an enclosing scope to // avoid rippling error messages on subsequent uses of the same type, // could be useful if #include was forgotten. return false; } /// \brief Determine the declaration specifier context from the declarator /// context. /// /// \param Context the declarator context, which is one of the /// Declarator::TheContext enumerator values. Parser::DeclSpecContext Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { if (Context == Declarator::MemberContext) return DSC_class; if (Context == Declarator::FileContext) return DSC_top_level; if (Context == Declarator::TrailingReturnContext) return DSC_trailing; return DSC_normal; } /// ParseAlignArgument - Parse the argument to an alignment-specifier. /// /// FIXME: Simply returns an alignof() expression if the argument is a /// type. Ideally, the type should be propagated directly into Sema. /// /// [C11] type-id /// [C11] constant-expression /// [C++0x] type-id ...[opt] /// [C++0x] assignment-expression ...[opt] ExprResult Parser::ParseAlignArgument(SourceLocation Start, SourceLocation &EllipsisLoc) { ExprResult ER; if (isTypeIdInParens()) { SourceLocation TypeLoc = Tok.getLocation(); ParsedType Ty = ParseTypeName().get(); SourceRange TypeRange(Start, Tok.getLocation()); ER = Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, Ty.getAsOpaquePtr(), TypeRange); } else ER = ParseConstantExpression(); if (getLangOpts().CPlusPlus0x && Tok.is(tok::ellipsis)) EllipsisLoc = ConsumeToken(); return ER; } /// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the /// attribute to Attrs. /// /// alignment-specifier: /// [C11] '_Alignas' '(' type-id ')' /// [C11] '_Alignas' '(' constant-expression ')' /// [C++0x] 'alignas' '(' type-id ...[opt] ')' /// [C++0x] 'alignas' '(' assignment-expression ...[opt] ')' void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *endLoc) { assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) && "Not an alignment-specifier!"); SourceLocation KWLoc = Tok.getLocation(); ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen)) return; SourceLocation EllipsisLoc; ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc); if (ArgExpr.isInvalid()) { SkipUntil(tok::r_paren); return; } T.consumeClose(); if (endLoc) *endLoc = T.getCloseLocation(); // FIXME: Handle pack-expansions here. if (EllipsisLoc.isValid()) { Diag(EllipsisLoc, diag::err_alignas_pack_exp_unsupported); return; } ExprVector ArgExprs(Actions); ArgExprs.push_back(ArgExpr.release()); Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc, 0, T.getOpenLocation(), ArgExprs.take(), 1, false, true); } /// ParseDeclarationSpecifiers /// declaration-specifiers: [C99 6.7] /// storage-class-specifier declaration-specifiers[opt] /// type-specifier declaration-specifiers[opt] /// [C99] function-specifier declaration-specifiers[opt] /// [C11] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] /// [Clang] '__module_private__' declaration-specifiers[opt] /// /// storage-class-specifier: [C99 6.7.1] /// 'typedef' /// 'extern' /// 'static' /// 'auto' /// 'register' /// [C++] 'mutable' /// [GNU] '__thread' /// function-specifier: [C99 6.7.4] /// [C99] 'inline' /// [C++] 'virtual' /// [C++] 'explicit' /// [OpenCL] '__kernel' /// 'friend': [C++ dcl.friend] /// 'constexpr': [C++0x dcl.constexpr] /// void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSContext, LateParsedAttrList *LateAttrs) { if (DS.getSourceRange().isInvalid()) { DS.SetRangeStart(Tok.getLocation()); DS.SetRangeEnd(Tok.getLocation()); } bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); while (1) { bool isInvalid = false; const char *PrevSpec = 0; unsigned DiagID = 0; SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { default: DoneWithDeclSpec: // [C++0x] decl-specifier-seq: decl-specifier attribute-specifier-seq[opt] MaybeParseCXX0XAttributes(DS.getAttributes()); // If this is not a declaration specifier token, we're done reading decl // specifiers. First verify that DeclSpec's are consistent. DS.Finish(Diags, PP); return; case tok::code_completion: { Sema::ParserCompletionContext CCC = Sema::PCC_Namespace; if (DS.hasTypeSpecifier()) { bool AllowNonIdentifiers = (getCurScope()->getFlags() & (Scope::ControlScope | Scope::BlockScope | Scope::TemplateParamScope | Scope::FunctionPrototypeScope | Scope::AtCatchScope)) == 0; bool AllowNestedNameSpecifiers = DSContext == DSC_top_level || (DSContext == DSC_class && DS.isFriendSpecified()); Actions.CodeCompleteDeclSpec(getCurScope(), DS, AllowNonIdentifiers, AllowNestedNameSpecifiers); return cutOffParsing(); } if (getCurScope()->getFnParent() || getCurScope()->getBlockParent()) CCC = Sema::PCC_LocalDeclarationSpecifiers; else if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) CCC = DSContext == DSC_class? Sema::PCC_MemberTemplate : Sema::PCC_Template; else if (DSContext == DSC_class) CCC = Sema::PCC_Class; else if (CurParsedObjCImpl) CCC = Sema::PCC_ObjCImplementation; Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); return cutOffParsing(); } case tok::coloncolon: // ::foo::bar // C++ scope specifier. Annotate and loop, or bail out on error. if (TryAnnotateCXXScopeToken(true)) { if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); goto DoneWithDeclSpec; } if (Tok.is(tok::coloncolon)) // ::new or ::delete goto DoneWithDeclSpec; continue; case tok::annot_cxxscope: { if (DS.hasTypeSpecifier()) goto DoneWithDeclSpec; CXXScopeSpec SS; Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); // We are looking for a qualified typename. Token Next = NextToken(); if (Next.is(tok::annot_template_id) && static_cast(Next.getAnnotationValue()) ->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A // C++ [class.qual]p2: // In a lookup in which the constructor is an acceptable lookup // result and the nested-name-specifier nominates a class C: // // - if the name specified after the // nested-name-specifier, when looked up in C, is the // injected-class-name of C (Clause 9), or // // - if the name specified after the nested-name-specifier // is the same as the identifier or the // simple-template-id's template-name in the last // component of the nested-name-specifier, // // the name is instead considered to name the constructor of // class C. // // Thus, if the template-name is actually the constructor // name, then the code is ill-formed; this interpretation is // reinforced by the NAD status of core issue 635. TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); if ((DSContext == DSC_top_level || (DSContext == DSC_class && DS.isFriendSpecified())) && TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) { if (isConstructorDeclarator()) { // The user meant this to be an out-of-line constructor // definition, but template arguments are not allowed // there. Just allow this as a constructor; we'll // complain about it later. goto DoneWithDeclSpec; } // The user meant this to name a type, but it actually names // a constructor with some extraneous template // arguments. Complain, then parse it as a type as the user // intended. Diag(TemplateId->TemplateNameLoc, diag::err_out_of_line_template_id_names_constructor) << TemplateId->Name; } DS.getTypeSpecScope() = SS; ConsumeToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); AnnotateTemplateIdTokenAsType(); continue; } if (Next.is(tok::annot_typename)) { DS.getTypeSpecScope() = SS; ConsumeToken(); // The C++ scope. if (Tok.getAnnotationValue()) { ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Tok.getAnnotationEndLoc(), PrevSpec, DiagID, T); } else DS.SetTypeSpecError(); DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // The typename } if (Next.isNot(tok::identifier)) goto DoneWithDeclSpec; // If we're in a context where the identifier could be a class name, // check whether this is a constructor declaration. if ((DSContext == DSC_top_level || (DSContext == DSC_class && DS.isFriendSpecified())) && Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(), &SS)) { if (isConstructorDeclarator()) goto DoneWithDeclSpec; // As noted in C++ [class.qual]p2 (cited above), when the name // of the class is qualified in a context where it could name // a constructor, its a constructor name. However, we've // looked at the declarator, and the user probably meant this // to be a type. Complain that it isn't supposed to be treated // as a type, then proceed to parse it as a type. Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor) << Next.getIdentifierInfo(); } ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS, false, false, ParsedType(), /*IsCtorOrDtorName=*/false, /*NonTrivialSourceInfo=*/true); // If the referenced identifier is not a type, then this declspec is // erroneous: We already checked about that it has no type specifier, and // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the // typename. if (TypeRep == 0) { ConsumeToken(); // Eat the scope spec so the identifier is current. if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext)) continue; goto DoneWithDeclSpec; } DS.getTypeSpecScope() = SS; ConsumeToken(); // The C++ scope. isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, TypeRep); if (isInvalid) break; DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // The typename. continue; } case tok::annot_typename: { if (Tok.getAnnotationValue()) { ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T); } else DS.SetTypeSpecError(); if (isInvalid) break; DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // The typename // Objective-C supports syntax of the form 'id' where 'id' // is a specific typedef and 'itf' where 'itf' is an // Objective-C interface. if (Tok.is(tok::less) && getLangOpts().ObjC1) ParseObjCProtocolQualifiers(DS); continue; } case tok::kw___is_signed: // GNU libstdc++ 4.4 uses __is_signed as an identifier, but Clang // typically treats it as a trait. If we see __is_signed as it appears // in libstdc++, e.g., // // static const bool __is_signed; // // then treat __is_signed as an identifier rather than as a keyword. if (DS.getTypeSpecType() == TST_bool && DS.getTypeQualifiers() == DeclSpec::TQ_const && DS.getStorageClassSpec() == DeclSpec::SCS_static) { Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); Tok.setKind(tok::identifier); } // We're done with the declaration-specifiers. goto DoneWithDeclSpec; // typedef-name case tok::kw_decltype: case tok::identifier: { // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. if (getLangOpts().CPlusPlus) { if (TryAnnotateCXXScopeToken(true)) { if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); goto DoneWithDeclSpec; } if (!Tok.is(tok::identifier)) continue; } // This identifier can only be a typedef name if we haven't already seen // a type-specifier. Without this check we misparse: // typedef int X; struct Y { short X; }; as 'short int'. if (DS.hasTypeSpecifier()) goto DoneWithDeclSpec; // Check for need to substitute AltiVec keyword tokens. if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) break; ParsedType TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope()); // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. if (!TypeRep) { if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext)) continue; goto DoneWithDeclSpec; } // If we're in a context where the identifier could be a class name, // check whether this is a constructor declaration. if (getLangOpts().CPlusPlus && DSContext == DSC_class && Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) && isConstructorDeclarator()) goto DoneWithDeclSpec; isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, TypeRep); if (isInvalid) break; DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // The identifier // Objective-C supports syntax of the form 'id' where 'id' // is a specific typedef and 'itf' where 'itf' is an // Objective-C interface. if (Tok.is(tok::less) && getLangOpts().ObjC1) ParseObjCProtocolQualifiers(DS); // Need to support trailing type qualifiers (e.g. "id

const"). // If a type specifier follows, it will be diagnosed elsewhere. continue; } // type-name case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind != TNK_Type_template) { // This template-id does not refer to a type name, so we're // done with the type-specifiers. goto DoneWithDeclSpec; } // If we're in a context where the template-id could be a // constructor name or specialization, check whether this is a // constructor declaration. if (getLangOpts().CPlusPlus && DSContext == DSC_class && Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) && isConstructorDeclarator()) goto DoneWithDeclSpec; // Turn the template-id annotation token into a type annotation // token, then try again to parse it as a type-specifier. AnnotateTemplateIdTokenAsType(); continue; } // GNU attributes support. case tok::kw___attribute: ParseGNUAttributes(DS.getAttributes(), 0, LateAttrs); continue; // Microsoft declspec support. case tok::kw___declspec: ParseMicrosoftDeclSpec(DS.getAttributes()); continue; // Microsoft single token adornments. case tok::kw___forceinline: // FIXME: Add handling here! break; case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___w64: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___unaligned: ParseMicrosoftTypeAttributes(DS.getAttributes()); continue; // Borland single token adornments. case tok::kw___pascal: ParseBorlandTypeAttributes(DS.getAttributes()); continue; // OpenCL single token adornments. case tok::kw___kernel: ParseOpenCLAttributes(DS.getAttributes()); continue; // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc, PrevSpec, DiagID); break; case tok::kw_extern: if (DS.isThreadSpecified()) Diag(Tok, diag::ext_thread_before) << "extern"; isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc, PrevSpec, DiagID); break; case tok::kw___private_extern__: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern, Loc, PrevSpec, DiagID); break; case tok::kw_static: if (DS.isThreadSpecified()) Diag(Tok, diag::ext_thread_before) << "static"; isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc, PrevSpec, DiagID); break; case tok::kw_auto: if (getLangOpts().CPlusPlus0x) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, PrevSpec, DiagID); if (!isInvalid) Diag(Tok, diag::ext_auto_storage_class) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); } else isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID); } else isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, PrevSpec, DiagID); break; case tok::kw_register: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc, PrevSpec, DiagID); break; case tok::kw_mutable: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_mutable, Loc, PrevSpec, DiagID); break; case tok::kw___thread: isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID); break; // function-specifier case tok::kw_inline: isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID); break; case tok::kw_virtual: isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec, DiagID); break; case tok::kw_explicit: isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID); break; // alignment-specifier case tok::kw__Alignas: if (!getLangOpts().C11) Diag(Tok, diag::ext_c11_alignas); ParseAlignmentSpecifier(DS.getAttributes()); continue; // friend case tok::kw_friend: if (DSContext == DSC_class) isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID); else { PrevSpec = ""; // not actually used by the diagnostic DiagID = diag::err_friend_invalid_in_context; isInvalid = true; } break; // Modules case tok::kw___module_private__: isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID); break; // constexpr case tok::kw_constexpr: isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); break; // type-specifier case tok::kw_short: isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID); break; case tok::kw_long: if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID); else isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID); break; case tok::kw___int64: isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID); break; case tok::kw_signed: isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); break; case tok::kw_unsigned: isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, DiagID); break; case tok::kw__Complex: isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec, DiagID); break; case tok::kw__Imaginary: isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec, DiagID); break; case tok::kw_void: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID); break; case tok::kw_char: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID); break; case tok::kw_int: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; case tok::kw___int128: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID); break; case tok::kw_half: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID); break; case tok::kw_float: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); break; case tok::kw_double: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID); break; case tok::kw_wchar_t: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID); break; case tok::kw_char16_t: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID); break; case tok::kw_char32_t: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID); break; case tok::kw_bool: case tok::kw__Bool: if (Tok.is(tok::kw_bool) && DS.getTypeSpecType() != DeclSpec::TST_unspecified && DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { PrevSpec = ""; // Not used by the diagnostic. DiagID = diag::err_bool_redeclaration; // For better error recovery. Tok.setKind(tok::identifier); isInvalid = true; } else { isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); } break; case tok::kw__Decimal32: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec, DiagID); break; case tok::kw__Decimal64: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec, DiagID); break; case tok::kw__Decimal128: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, DiagID); break; case tok::kw___vector: isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); break; case tok::kw___pixel: isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); break; case tok::kw___unknown_anytype: isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, PrevSpec, DiagID); break; // class-specifier: case tok::kw_class: case tok::kw_struct: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); ConsumeToken(); ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS, EnteringContext, DSContext); continue; } // enum-specifier: case tok::kw_enum: ConsumeToken(); ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext); continue; // cv-qualifier: case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID, getLangOpts()); break; case tok::kw_volatile: isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, getLangOpts()); break; case tok::kw_restrict: isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, getLangOpts()); break; // C++ typename-specifier: case tok::kw_typename: if (TryAnnotateTypeOrScopeToken()) { DS.SetTypeSpecError(); goto DoneWithDeclSpec; } if (!Tok.is(tok::kw_typename)) continue; break; // GNU typeof support. case tok::kw_typeof: ParseTypeofSpecifier(DS); continue; case tok::annot_decltype: ParseDecltypeSpecifier(DS); continue; case tok::kw___underlying_type: ParseUnderlyingTypeSpecifier(DS); continue; case tok::kw__Atomic: ParseAtomicSpecifier(DS); continue; // OpenCL qualifiers: case tok::kw_private: if (!getLangOpts().OpenCL) goto DoneWithDeclSpec; case tok::kw___private: case tok::kw___global: case tok::kw___local: case tok::kw___constant: case tok::kw___read_only: case tok::kw___write_only: case tok::kw___read_write: ParseOpenCLQualifiers(DS); break; case tok::less: // GCC ObjC supports types like "" as a synonym for // "id". This is hopelessly old fashioned and dangerous, // but we support it. if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1) goto DoneWithDeclSpec; if (!ParseObjCProtocolQualifiers(DS)) Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) << FixItHint::CreateInsertion(Loc, "id") << SourceRange(Loc, DS.getSourceRange().getEnd()); // Need to support trailing type qualifiers (e.g. "id

const"). // If a type specifier follows, it will be diagnosed elsewhere. continue; } // If the specifier wasn't legal, issue a diagnostic. if (isInvalid) { assert(PrevSpec && "Method did not return previous specifier!"); assert(DiagID); if (DiagID == diag::ext_duplicate_declspec) Diag(Tok, DiagID) << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); else Diag(Tok, DiagID) << PrevSpec; } DS.SetRangeEnd(Tok.getLocation()); if (DiagID != diag::err_bool_redeclaration) ConsumeToken(); } } /// ParseStructDeclaration - Parse a struct declaration without the terminating /// semicolon. /// /// struct-declaration: /// specifier-qualifier-list struct-declarator-list /// [GNU] __extension__ struct-declaration /// [GNU] specifier-qualifier-list /// struct-declarator-list: /// struct-declarator /// struct-declarator-list ',' struct-declarator /// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator /// struct-declarator: /// declarator /// [GNU] declarator attributes[opt] /// declarator[opt] ':' constant-expression /// [GNU] declarator[opt] ':' constant-expression attributes[opt] /// void Parser:: ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { if (Tok.is(tok::kw___extension__)) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); return ParseStructDeclaration(DS, Fields); } // Parse the common specifier-qualifiers-list piece. ParseSpecifierQualifierList(DS); // If there are no declarators, this is a free-standing declaration // specifier. Let the actions module cope with it. if (Tok.is(tok::semi)) { Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS); return; } // Read struct-declarators until we find the semicolon. bool FirstDeclarator = true; SourceLocation CommaLoc; while (1) { ParsingDeclRAIIObject PD(*this); FieldDeclarator DeclaratorInfo(DS); DeclaratorInfo.D.setCommaLoc(CommaLoc); // Attributes are only allowed here on successive declarators. if (!FirstDeclarator) MaybeParseGNUAttributes(DeclaratorInfo.D); /// struct-declarator: declarator /// struct-declarator: declarator[opt] ':' constant-expression if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. ColonProtectionRAIIObject X(*this); ParseDeclarator(DeclaratorInfo.D); } if (Tok.is(tok::colon)) { ConsumeToken(); ExprResult Res(ParseConstantExpression()); if (Res.isInvalid()) SkipUntil(tok::semi, true, true); else DeclaratorInfo.BitfieldSize = Res.release(); } // If attributes exist after the declarator, parse them. MaybeParseGNUAttributes(DeclaratorInfo.D); // We're done with this declarator; invoke the callback. Decl *D = Fields.invoke(DeclaratorInfo); PD.complete(D); // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) return; // Consume the comma. CommaLoc = ConsumeToken(); FirstDeclarator = false; } } /// ParseStructUnionBody /// struct-contents: /// struct-declaration-list /// [EXT] empty /// [GNU] "struct-declaration-list" without terminatoring ';' /// struct-declaration-list: /// struct-declaration /// struct-declaration-list struct-declaration /// [OBC] '@' 'defs' '(' class-name ')' /// void Parser::ParseStructUnionBody(SourceLocation RecordLoc, unsigned TagType, Decl *TagDecl) { PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, "parsing struct/union body"); BalancedDelimiterTracker T(*this, tok::l_brace); if (T.consumeOpen()) return; ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in // C++. if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) { Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union); Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union); } SmallVector FieldDecls; // While we still have something to read, read the declarations in the struct. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // Each iteration of this loop reads one struct-declaration. // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } // Parse all the comma separated declarators. DeclSpec DS(AttrFactory); if (!Tok.is(tok::at)) { struct CFieldCallback : FieldCallback { Parser &P; Decl *TagDecl; SmallVectorImpl &FieldDecls; CFieldCallback(Parser &P, Decl *TagDecl, SmallVectorImpl &FieldDecls) : P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {} virtual Decl *invoke(FieldDeclarator &FD) { // Install the declarator into the current TagDecl. Decl *Field = P.Actions.ActOnField(P.getCurScope(), TagDecl, FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D, FD.BitfieldSize); FieldDecls.push_back(Field); return Field; } } Callback(*this, TagDecl, FieldDecls); ParseStructDeclaration(DS, Callback); } else { // Handle @defs ConsumeToken(); if (!Tok.isObjCAtKeyword(tok::objc_defs)) { Diag(Tok, diag::err_unexpected_at); SkipUntil(tok::semi, true); continue; } ConsumeToken(); ExpectAndConsume(tok::l_paren, diag::err_expected_lparen); if (!Tok.is(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::semi, true); continue; } SmallVector Fields; Actions.ActOnDefs(getCurScope(), TagDecl, Tok.getLocation(), Tok.getIdentifierInfo(), Fields); FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end()); ConsumeToken(); ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); } if (Tok.is(tok::semi)) { ConsumeToken(); } else if (Tok.is(tok::r_brace)) { ExpectAndConsume(tok::semi, diag::ext_expected_semi_decl_list); break; } else { ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); // Skip to end of block or statement to avoid ext-warning on extra ';'. SkipUntil(tok::r_brace, true, true); // If we stopped at a ';', eat it. if (Tok.is(tok::semi)) ConsumeToken(); } } T.consumeClose(); ParsedAttributes attrs(AttrFactory); // If attributes exist after struct contents, parse them. MaybeParseGNUAttributes(attrs); Actions.ActOnFields(getCurScope(), RecordLoc, TagDecl, FieldDecls, T.getOpenLocation(), T.getCloseLocation(), attrs.getList()); StructScope.Exit(); Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, T.getCloseLocation()); } /// ParseEnumSpecifier /// enum-specifier: [C99 6.7.2.2] /// 'enum' identifier[opt] '{' enumerator-list '}' ///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}' /// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt] /// '}' attributes[opt] /// [MS] 'enum' __declspec[opt] identifier[opt] '{' enumerator-list ',' [opt] /// '}' /// 'enum' identifier /// [GNU] 'enum' attributes[opt] identifier /// /// [C++11] enum-head '{' enumerator-list[opt] '}' /// [C++11] enum-head '{' enumerator-list ',' '}' /// /// enum-head: [C++11] /// enum-key attribute-specifier-seq[opt] identifier[opt] enum-base[opt] /// enum-key attribute-specifier-seq[opt] nested-name-specifier /// identifier enum-base[opt] /// /// enum-key: [C++11] /// 'enum' /// 'enum' 'class' /// 'enum' 'struct' /// /// enum-base: [C++11] /// ':' type-specifier-seq /// /// [C++] elaborated-type-specifier: /// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier /// void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC) { // Parse the tag portion of this. if (Tok.is(tok::code_completion)) { // Code completion for an enum name. Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum); return cutOffParsing(); } SourceLocation ScopedEnumKWLoc; bool IsScopedUsingClassTag = false; if (getLangOpts().CPlusPlus0x && (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) { Diag(Tok, diag::warn_cxx98_compat_scoped_enum); IsScopedUsingClassTag = Tok.is(tok::kw_class); ScopedEnumKWLoc = ConsumeToken(); } // C++11 [temp.explicit]p12: The usual access controls do not apply to names // used to specify explicit instantiations. We extend this to also cover // explicit specializations. Sema::SuppressAccessChecksRAII SuppressAccess(Actions, TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); // If attributes exist after tag, parse them. ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); // If declspecs exist after tag, parse them. while (Tok.is(tok::kw___declspec)) ParseMicrosoftDeclSpec(attrs); // Enum definitions should not be parsed in a trailing-return-type. bool AllowDeclaration = DSC != DSC_trailing; bool AllowFixedUnderlyingType = AllowDeclaration && (getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt || getLangOpts().ObjC2); CXXScopeSpec &SS = DS.getTypeSpecScope(); if (getLangOpts().CPlusPlus) { // "enum foo : bar;" is not a potential typo for "enum foo::bar;" // if a fixed underlying type is allowed. ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType); if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false)) return; if (SS.isSet() && Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); if (Tok.isNot(tok::l_brace)) { // Has no name and is not a definition. // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, true); return; } } } // Must have either 'enum name' or 'enum {...}'. if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) && !(AllowFixedUnderlyingType && Tok.is(tok::colon))) { Diag(Tok, diag::err_expected_ident_lbrace); // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, true); return; } // If an identifier is present, consume and remember it. IdentifierInfo *Name = 0; SourceLocation NameLoc; if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); } if (!Name && ScopedEnumKWLoc.isValid()) { // C++0x 7.2p2: The optional identifier shall not be omitted in the // declaration of a scoped enumeration. Diag(Tok, diag::err_scoped_enum_missing_identifier); ScopedEnumKWLoc = SourceLocation(); IsScopedUsingClassTag = false; } // Stop suppressing access control now we've parsed the enum name. SuppressAccess.done(); TypeResult BaseType; // Parse the fixed underlying type. if (AllowFixedUnderlyingType && Tok.is(tok::colon)) { bool PossibleBitfield = false; if (getCurScope()->getFlags() & Scope::ClassScope) { // If we're in class scope, this can either be an enum declaration with // an underlying type, or a declaration of a bitfield member. We try to // use a simple disambiguation scheme first to catch the common cases // (integer literal, sizeof); if it's still ambiguous, we then consider // anything that's a simple-type-specifier followed by '(' as an // expression. This suffices because function types are not valid // underlying types anyway. TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind()); // If the next token starts an expression, we know we're parsing a // bit-field. This is the common case. if (TPR == TPResult::True()) PossibleBitfield = true; // If the next token starts a type-specifier-seq, it may be either a // a fixed underlying type or the start of a function-style cast in C++; // lookahead one more token to see if it's obvious that we have a // fixed underlying type. else if (TPR == TPResult::False() && GetLookAheadToken(2).getKind() == tok::semi) { // Consume the ':'. ConsumeToken(); } else { // We have the start of a type-specifier-seq, so we have to perform // tentative parsing to determine whether we have an expression or a // type. TentativeParsingAction TPA(*this); // Consume the ':'. ConsumeToken(); // If we see a type specifier followed by an open-brace, we have an // ambiguity between an underlying type and a C++11 braced // function-style cast. Resolve this by always treating it as an // underlying type. // FIXME: The standard is not entirely clear on how to disambiguate in // this case. if ((getLangOpts().CPlusPlus && isCXXDeclarationSpecifier(TPResult::True()) != TPResult::True()) || (!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) { // We'll parse this as a bitfield later. PossibleBitfield = true; TPA.Revert(); } else { // We have a type-specifier-seq. TPA.Commit(); } } } else { // Consume the ':'. ConsumeToken(); } if (!PossibleBitfield) { SourceRange Range; BaseType = ParseTypeName(&Range); if (!getLangOpts().CPlusPlus0x && !getLangOpts().ObjC2) Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type) << Range; if (getLangOpts().CPlusPlus0x) Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type); } } // There are four options here. If we have 'friend enum foo;' then this is a // friend declaration, and cannot have an accompanying definition. If we have // 'enum foo;', then this is a forward declaration. If we have // 'enum foo {...' then this is a definition. Otherwise we have something // like 'enum foo xyz', a reference. // // This is needed to handle stuff like this right (C99 6.7.2.3p11): // enum foo {..}; void bar() { enum foo; } <- new foo in bar. // enum foo {..}; void bar() { enum foo x; } <- use of old foo. // Sema::TagUseKind TUK; if (DS.isFriendSpecified()) TUK = Sema::TUK_Friend; else if (!AllowDeclaration) TUK = Sema::TUK_Reference; else if (Tok.is(tok::l_brace)) TUK = Sema::TUK_Definition; else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) TUK = Sema::TUK_Declaration; else TUK = Sema::TUK_Reference; MultiTemplateParamsArg TParams; if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && TUK != Sema::TUK_Reference) { if (!getLangOpts().CPlusPlus0x || !SS.isSet()) { // Skip the rest of this declarator, up until the comma or semicolon. Diag(Tok, diag::err_enum_template); SkipUntil(tok::comma, true); return; } if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { // Enumerations can't be explicitly instantiated. DS.SetTypeSpecError(); Diag(StartLoc, diag::err_explicit_instantiation_enum); return; } assert(TemplateInfo.TemplateParams && "no template parameters"); TParams = MultiTemplateParamsArg(TemplateInfo.TemplateParams->data(), TemplateInfo.TemplateParams->size()); } if (!Name && TUK != Sema::TUK_Definition) { Diag(Tok, diag::err_enumerator_unnamed_no_def); // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, true); return; } bool Owned = false; bool IsDependent = false; const char *PrevSpec = 0; unsigned DiagID; Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType); if (IsDependent) { // This enum has a dependent nested-name-specifier. Handle it as a // dependent tag. if (!Name) { DS.SetTypeSpecError(); Diag(Tok, diag::err_expected_type_name_after_typename); return; } TypeResult Type = Actions.ActOnDependentTag(getCurScope(), DeclSpec::TST_enum, TUK, SS, Name, StartLoc, NameLoc); if (Type.isInvalid()) { DS.SetTypeSpecError(); return; } if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, DiagID, Type.get())) Diag(StartLoc, DiagID) << PrevSpec; return; } if (!TagDecl) { // The action failed to produce an enumeration tag. If this is a // definition, consume the entire definition. if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { ConsumeBrace(); SkipUntil(tok::r_brace); } DS.SetTypeSpecError(); return; } if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { if (TUK == Sema::TUK_Friend) { Diag(Tok, diag::err_friend_decl_defines_type) << SourceRange(DS.getFriendSpecLoc()); ConsumeBrace(); SkipUntil(tok::r_brace); } else { ParseEnumBody(StartLoc, TagDecl); } } if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, DiagID, TagDecl, Owned)) Diag(StartLoc, DiagID) << PrevSpec; } /// ParseEnumBody - Parse a {} enclosed enumerator-list. /// enumerator-list: /// enumerator /// enumerator-list ',' enumerator /// enumerator: /// enumeration-constant /// enumeration-constant '=' constant-expression /// enumeration-constant: /// identifier /// void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // Enter the scope of the enum body and start the definition. ParseScope EnumScope(this, Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl); BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); // C does not allow an empty enumerator-list, C++ does [dcl.enum]. if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) Diag(Tok, diag::error_empty_enum); SmallVector EnumConstantDecls; Decl *LastEnumConstDecl = 0; // Parse the enumerator-list. while (Tok.is(tok::identifier)) { IdentifierInfo *Ident = Tok.getIdentifierInfo(); SourceLocation IdentLoc = ConsumeToken(); // If attributes exist after the enumerator, parse them. ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); SourceLocation EqualLoc; ExprResult AssignedVal; ParsingDeclRAIIObject PD(*this); if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); AssignedVal = ParseConstantExpression(); if (AssignedVal.isInvalid()) SkipUntil(tok::comma, tok::r_brace, true, true); } // Install the enumerator constant into EnumDecl. Decl *EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl, LastEnumConstDecl, IdentLoc, Ident, attrs.getList(), EqualLoc, AssignedVal.release()); PD.complete(EnumConstDecl); EnumConstantDecls.push_back(EnumConstDecl); LastEnumConstDecl = EnumConstDecl; if (Tok.is(tok::identifier)) { // We're missing a comma between enumerators. SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); Diag(Loc, diag::err_enumerator_list_missing_comma) << FixItHint::CreateInsertion(Loc, ", "); continue; } if (Tok.isNot(tok::comma)) break; SourceLocation CommaLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) { if (!getLangOpts().C99 && !getLangOpts().CPlusPlus0x) Diag(CommaLoc, diag::ext_enumerator_list_comma) << getLangOpts().CPlusPlus << FixItHint::CreateRemoval(CommaLoc); else if (getLangOpts().CPlusPlus0x) Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma) << FixItHint::CreateRemoval(CommaLoc); } } // Eat the }. T.consumeClose(); // If attributes exist after the identifier list, parse them. ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); Actions.ActOnEnumBody(StartLoc, T.getOpenLocation(), T.getCloseLocation(), EnumDecl, EnumConstantDecls.data(), EnumConstantDecls.size(), getCurScope(), attrs.getList()); EnumScope.Exit(); Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, T.getCloseLocation()); } /// isTypeSpecifierQualifier - Return true if the current token could be the /// start of a type-qualifier-list. bool Parser::isTypeQualifier() const { switch (Tok.getKind()) { default: return false; // type-qualifier only in OpenCL case tok::kw_private: return getLangOpts().OpenCL; // type-qualifier case tok::kw_const: case tok::kw_volatile: case tok::kw_restrict: case tok::kw___private: case tok::kw___local: case tok::kw___global: case tok::kw___constant: case tok::kw___read_only: case tok::kw___read_write: case tok::kw___write_only: return true; } } /// isKnownToBeTypeSpecifier - Return true if we know that the specified token /// is definitely a type-specifier. Return false if it isn't part of a type /// specifier or if we're not sure. bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { switch (Tok.getKind()) { default: return false; // type-specifiers 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__Complex: case tok::kw__Imaginary: case tok::kw_void: case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_int: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: case tok::kw___vector: // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: case tok::kw_union: // enum-specifier case tok::kw_enum: // typedef-name case tok::annot_typename: return true; } } /// isTypeSpecifierQualifier - Return true if the current token could be the /// start of a specifier-qualifier-list. bool Parser::isTypeSpecifierQualifier() { switch (Tok.getKind()) { default: return false; case tok::identifier: // foo::bar if (TryAltiVecVectorToken()) return true; // Fall through. case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return true; if (Tok.is(tok::identifier)) return false; return isTypeSpecifierQualifier(); case tok::coloncolon: // ::foo::bar if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return false; if (TryAnnotateTypeOrScopeToken()) return true; return isTypeSpecifierQualifier(); // GNU attributes support. case tok::kw___attribute: // GNU typeof support. case tok::kw_typeof: // type-specifiers 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__Complex: case tok::kw__Imaginary: case tok::kw_void: case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_int: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: case tok::kw___vector: // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: case tok::kw_union: // enum-specifier case tok::kw_enum: // type-qualifier case tok::kw_const: case tok::kw_volatile: case tok::kw_restrict: // typedef-name case tok::annot_typename: return true; // GNU ObjC bizarre protocol extension: with implicit 'id'. case tok::less: return getLangOpts().ObjC1; case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___pascal: case tok::kw___unaligned: case tok::kw___private: case tok::kw___local: case tok::kw___global: case tok::kw___constant: case tok::kw___read_only: case tok::kw___read_write: case tok::kw___write_only: return true; case tok::kw_private: return getLangOpts().OpenCL; // C11 _Atomic() case tok::kw__Atomic: return true; } } /// isDeclarationSpecifier() - Return true if the current token is part of a /// declaration specifier. /// /// \param DisambiguatingWithExpression True to indicate that the purpose of /// this check is to disambiguate between an expression and a declaration. bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { switch (Tok.getKind()) { default: return false; case tok::kw_private: return getLangOpts().OpenCL; case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. if (getLangOpts().ObjC1 && NextToken().is(tok::period)) return false; if (TryAltiVecVectorToken()) return true; // Fall through. case tok::kw_decltype: // decltype(T())::type case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return true; if (Tok.is(tok::identifier)) return false; // If we're in Objective-C and we have an Objective-C class type followed // by an identifier and then either ':' or ']', in a place where an // expression is permitted, then this is probably a class message send // missing the initial '['. In this case, we won't consider this to be // the start of a declaration. if (DisambiguatingWithExpression && isStartOfObjCClassMessageMissingOpenBracket()) return false; return isDeclarationSpecifier(); case tok::coloncolon: // ::foo::bar if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return false; // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return true; return isDeclarationSpecifier(); // storage-class-specifier case tok::kw_typedef: case tok::kw_extern: case tok::kw___private_extern__: case tok::kw_static: case tok::kw_auto: case tok::kw_register: case tok::kw___thread: // Modules case tok::kw___module_private__: // type-specifiers 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__Complex: case tok::kw__Imaginary: case tok::kw_void: case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_int: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: case tok::kw___vector: // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: case tok::kw_union: // enum-specifier case tok::kw_enum: // type-qualifier case tok::kw_const: case tok::kw_volatile: case tok::kw_restrict: // function-specifier case tok::kw_inline: case tok::kw_virtual: case tok::kw_explicit: // static_assert-declaration case tok::kw__Static_assert: // GNU typeof support. case tok::kw_typeof: // GNU attributes. case tok::kw___attribute: return true; // C++0x decltype. case tok::annot_decltype: return true; // C11 _Atomic() case tok::kw__Atomic: return true; // GNU ObjC bizarre protocol extension: with implicit 'id'. case tok::less: return getLangOpts().ObjC1; // typedef-name case tok::annot_typename: return !DisambiguatingWithExpression || !isStartOfObjCClassMessageMissingOpenBracket(); case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___forceinline: case tok::kw___pascal: case tok::kw___unaligned: case tok::kw___private: case tok::kw___local: case tok::kw___global: case tok::kw___constant: case tok::kw___read_only: case tok::kw___read_write: case tok::kw___write_only: return true; } } bool Parser::isConstructorDeclarator() { TentativeParsingAction TPA(*this); // Parse the C++ scope specifier. CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/true)) { TPA.Revert(); return false; } // Parse the constructor name. if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { // We already know that we have a constructor name; just consume // the token. ConsumeToken(); } else { TPA.Revert(); return false; } // Current class name must be followed by a left parenthesis. if (Tok.isNot(tok::l_paren)) { TPA.Revert(); return false; } ConsumeParen(); // A right parenthesis, or ellipsis followed by a right parenthesis signals // that we have a constructor. if (Tok.is(tok::r_paren) || (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren))) { TPA.Revert(); return true; } // If we need to, enter the specified scope. DeclaratorScopeObj DeclScopeObj(*this, SS); if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS)) DeclScopeObj.EnterDeclaratorScope(); // Optionally skip Microsoft attributes. ParsedAttributes Attrs(AttrFactory); MaybeParseMicrosoftAttributes(Attrs); // Check whether the next token(s) are part of a declaration // specifier, in which case we have the start of a parameter and, // therefore, we know that this is a constructor. bool IsConstructor = false; if (isDeclarationSpecifier()) IsConstructor = true; else if (Tok.is(tok::identifier) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) { // We've seen "C ( X" or "C ( X::Y", but "X" / "X::Y" is not a type. // This might be a parenthesized member name, but is more likely to // be a constructor declaration with an invalid argument type. Keep // looking. if (Tok.is(tok::annot_cxxscope)) ConsumeToken(); ConsumeToken(); // If this is not a constructor, we must be parsing a declarator, // which must have one of the following syntactic forms (see the // grammar extract at the start of ParseDirectDeclarator): switch (Tok.getKind()) { case tok::l_paren: // C(X ( int)); case tok::l_square: // C(X [ 5]); // C(X [ [attribute]]); case tok::coloncolon: // C(X :: Y); // C(X :: *p); case tok::r_paren: // C(X ) // Assume this isn't a constructor, rather than assuming it's a // constructor with an unnamed parameter of an ill-formed type. break; default: IsConstructor = true; break; } } TPA.Revert(); return IsConstructor; } /// ParseTypeQualifierListOpt /// type-qualifier-list: [C99 6.7.5] /// type-qualifier /// [vendor] attributes /// [ only if VendorAttributesAllowed=true ] /// type-qualifier-list type-qualifier /// [vendor] type-qualifier-list attributes /// [ only if VendorAttributesAllowed=true ] /// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq /// [ only if CXX0XAttributesAllowed=true ] /// Note: vendor can be GNU, MS, etc. /// void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool VendorAttributesAllowed, bool CXX11AttributesAllowed) { if (getLangOpts().CPlusPlus0x && CXX11AttributesAllowed && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); ParseCXX11Attributes(attrs); DS.takeAttributesFrom(attrs); } SourceLocation EndLoc; while (1) { bool isInvalid = false; const char *PrevSpec = 0; unsigned DiagID = 0; SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { case tok::code_completion: Actions.CodeCompleteTypeQualifiers(DS); return cutOffParsing(); case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, getLangOpts()); break; case tok::kw_volatile: isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, getLangOpts()); break; case tok::kw_restrict: isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, getLangOpts()); break; // OpenCL qualifiers: case tok::kw_private: if (!getLangOpts().OpenCL) goto DoneWithTypeQuals; case tok::kw___private: case tok::kw___global: case tok::kw___local: case tok::kw___constant: case tok::kw___read_only: case tok::kw___write_only: case tok::kw___read_write: ParseOpenCLQualifiers(DS); break; case tok::kw___w64: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___unaligned: if (VendorAttributesAllowed) { ParseMicrosoftTypeAttributes(DS.getAttributes()); continue; } goto DoneWithTypeQuals; case tok::kw___pascal: if (VendorAttributesAllowed) { ParseBorlandTypeAttributes(DS.getAttributes()); continue; } goto DoneWithTypeQuals; case tok::kw___attribute: if (VendorAttributesAllowed) { ParseGNUAttributes(DS.getAttributes()); continue; // do *not* consume the next token! } // otherwise, FALL THROUGH! default: DoneWithTypeQuals: // If this is not a type-qualifier token, we're done reading type // qualifiers. First verify that DeclSpec's are consistent. DS.Finish(Diags, PP); if (EndLoc.isValid()) DS.SetRangeEnd(EndLoc); return; } // If the specifier combination wasn't legal, issue a diagnostic. if (isInvalid) { assert(PrevSpec && "Method did not return previous specifier!"); Diag(Tok, DiagID) << PrevSpec; } EndLoc = ConsumeToken(); } } /// ParseDeclarator - Parse and verify a newly-initialized declarator. /// void Parser::ParseDeclarator(Declarator &D) { /// This implements the 'declarator' production in the C grammar, then checks /// for well-formedness and issues diagnostics. ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); } static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang) { if (Kind == tok::star || Kind == tok::caret) return true; // We parse rvalue refs in C++03, because otherwise the errors are scary. if (!Lang.CPlusPlus) return false; return Kind == tok::amp || Kind == tok::ampamp; } /// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator /// is parsed by the function passed to it. Pass null, and the direct-declarator /// isn't parsed at all, making this function effectively parse the C++ /// ptr-operator production. /// /// If the grammar of this construct is extended, matching changes must also be /// made to TryParseDeclarator and MightBeDeclarator, and possibly to /// isConstructorDeclarator. /// /// declarator: [C99 6.7.5] [C++ 8p4, dcl.decl] /// [C] pointer[opt] direct-declarator /// [C++] direct-declarator /// [C++] ptr-operator declarator /// /// pointer: [C99 6.7.5] /// '*' type-qualifier-list[opt] /// '*' type-qualifier-list[opt] pointer /// /// ptr-operator: /// '*' cv-qualifier-seq[opt] /// '&' /// [C++0x] '&&' /// [GNU] '&' restrict[opt] attributes[opt] /// [GNU?] '&&' restrict[opt] attributes[opt] /// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] void Parser::ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser) { if (Diags.hasAllExtensionsSilenced()) D.setExtension(); // C++ member pointers start with a '::' or a nested-name. // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. if (getLangOpts().CPlusPlus && (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope))) { bool EnteringContext = D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext; CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext); if (SS.isNotEmpty()) { if (Tok.isNot(tok::star)) { // The scope spec really belongs to the direct-declarator. D.getCXXScopeSpec() = SS; if (DirectDeclParser) (this->*DirectDeclParser)(D); return; } SourceLocation Loc = ConsumeToken(); D.SetRangeEnd(Loc); DeclSpec DS(AttrFactory); ParseTypeQualifierListOpt(DS); D.ExtendWithDeclSpec(DS); // Recurse to parse whatever is left. ParseDeclaratorInternal(D, DirectDeclParser); // Sema will have to catch (syntactically invalid) pointers into global // scope. It has to catch pointers into namespace scope anyway. D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(), Loc), DS.getAttributes(), /* Don't replace range end. */SourceLocation()); return; } } tok::TokenKind Kind = Tok.getKind(); // Not a pointer, C++ reference, or block. if (!isPtrOperatorToken(Kind, getLangOpts())) { if (DirectDeclParser) (this->*DirectDeclParser)(D); return; } // Otherwise, '*' -> pointer, '^' -> block, '&' -> lvalue reference, // '&&' -> rvalue reference SourceLocation Loc = ConsumeToken(); // Eat the *, ^, & or &&. D.SetRangeEnd(Loc); if (Kind == tok::star || Kind == tok::caret) { // Is a pointer. DeclSpec DS(AttrFactory); // FIXME: GNU attributes are not allowed here in a new-type-id. ParseTypeQualifierListOpt(DS); D.ExtendWithDeclSpec(DS); // Recursively parse the declarator. ParseDeclaratorInternal(D, DirectDeclParser); if (Kind == tok::star) // Remember that we parsed a pointer type, and remember the type-quals. D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, DS.getConstSpecLoc(), DS.getVolatileSpecLoc(), DS.getRestrictSpecLoc()), DS.getAttributes(), SourceLocation()); else // Remember that we parsed a Block type, and remember the type-quals. D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(), Loc), DS.getAttributes(), SourceLocation()); } else { // Is a reference DeclSpec DS(AttrFactory); // Complain about rvalue references in C++03, but then go on and build // the declarator. if (Kind == tok::ampamp) Diag(Loc, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_rvalue_reference : diag::ext_rvalue_reference); // GNU-style and C++11 attributes are allowed here, as is restrict. ParseTypeQualifierListOpt(DS); D.ExtendWithDeclSpec(DS); // C++ 8.3.2p1: cv-qualified references are ill-formed except when the // cv-qualifiers are introduced through the use of a typedef or of a // template type argument, in which case the cv-qualifiers are ignored. if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), diag::err_invalid_reference_qualifier_application) << "const"; if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getVolatileSpecLoc(), diag::err_invalid_reference_qualifier_application) << "volatile"; } // Recursively parse the declarator. ParseDeclaratorInternal(D, DirectDeclParser); if (D.getNumTypeObjects() > 0) { // C++ [dcl.ref]p4: There shall be no references to references. DeclaratorChunk& InnerChunk = D.getTypeObject(D.getNumTypeObjects() - 1); if (InnerChunk.Kind == DeclaratorChunk::Reference) { if (const IdentifierInfo *II = D.getIdentifier()) Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference) << II; else Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference) << "type name"; // Once we've complained about the reference-to-reference, we // can go ahead and build the (technically ill-formed) // declarator: reference collapsing will take care of it. } } // Remember that we parsed a reference type. It doesn't have type-quals. D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, Kind == tok::amp), DS.getAttributes(), SourceLocation()); } } static void diagnoseMisplacedEllipsis(Parser &P, Declarator &D, SourceLocation EllipsisLoc) { if (EllipsisLoc.isValid()) { FixItHint Insertion; if (!D.getEllipsisLoc().isValid()) { Insertion = FixItHint::CreateInsertion(D.getIdentifierLoc(), "..."); D.setEllipsisLoc(EllipsisLoc); } P.Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration) << FixItHint::CreateRemoval(EllipsisLoc) << Insertion << !D.hasName(); } } /// ParseDirectDeclarator /// direct-declarator: [C99 6.7.5] /// [C99] identifier /// '(' declarator ')' /// [GNU] '(' attributes declarator ')' /// [C90] direct-declarator '[' constant-expression[opt] ']' /// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' /// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' /// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' /// [C++11] direct-declarator '[' constant-expression[opt] ']' /// attribute-specifier-seq[opt] /// direct-declarator '(' parameter-type-list ')' /// direct-declarator '(' identifier-list[opt] ')' /// [GNU] direct-declarator '(' parameter-forward-declarations /// parameter-type-list[opt] ')' /// [C++] direct-declarator '(' parameter-declaration-clause ')' /// cv-qualifier-seq[opt] exception-specification[opt] /// [C++11] direct-declarator '(' parameter-declaration-clause ')' /// attribute-specifier-seq[opt] cv-qualifier-seq[opt] /// ref-qualifier[opt] exception-specification[opt] /// [C++] declarator-id /// [C++11] declarator-id attribute-specifier-seq[opt] /// /// declarator-id: [C++ 8] /// '...'[opt] id-expression /// '::'[opt] nested-name-specifier[opt] type-name /// /// id-expression: [C++ 5.1] /// unqualified-id /// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id /// conversion-function-id /// '~' class-name /// template-id /// /// Note, any additional constructs added here may need corresponding changes /// in isConstructorDeclarator. void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { // ParseDeclaratorInternal might already have parsed the scope. if (D.getCXXScopeSpec().isEmpty()) { bool EnteringContext = D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext; ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), EnteringContext); } if (D.getCXXScopeSpec().isValid()) { if (Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); } // C++0x [dcl.fct]p14: // There is a syntactic ambiguity when an ellipsis occurs at the end // of a parameter-declaration-clause without a preceding comma. In // this case, the ellipsis is parsed as part of the // abstract-declarator if the type of the parameter names a template // parameter pack that has not been expanded; otherwise, it is parsed // as part of the parameter-declaration-clause. if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() && !((D.getContext() == Declarator::PrototypeContext || D.getContext() == Declarator::BlockLiteralContext) && NextToken().is(tok::r_paren) && !Actions.containsUnexpandedParameterPacks(D))) { SourceLocation EllipsisLoc = ConsumeToken(); if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) { // The ellipsis was put in the wrong place. Recover, and explain to // the user what they should have done. ParseDeclarator(D); diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); return; } else D.setEllipsisLoc(EllipsisLoc); // The ellipsis can't be followed by a parenthesized declarator. We // check for that in ParseParenDeclarator, after we have disambiguated // the l_paren token. } if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { // We found something that indicates the start of an unqualified-id. // Parse that unqualified-id. bool AllowConstructorName; if (D.getDeclSpec().hasTypeSpecifier()) AllowConstructorName = false; else if (D.getCXXScopeSpec().isSet()) AllowConstructorName = (D.getContext() == Declarator::FileContext || (D.getContext() == Declarator::MemberContext && D.getDeclSpec().isFriendSpecified())); else AllowConstructorName = (D.getContext() == Declarator::MemberContext); SourceLocation TemplateKWLoc; if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, AllowConstructorName, ParsedType(), TemplateKWLoc, D.getName()) || // Once we're past the identifier, if the scope was bad, mark the // whole declarator bad. D.getCXXScopeSpec().isInvalid()) { D.SetIdentifier(0, Tok.getLocation()); D.setInvalidType(true); } else { // Parsed the unqualified-id; update range information and move along. if (D.getSourceRange().getBegin().isInvalid()) D.SetRangeBegin(D.getName().getSourceRange().getBegin()); D.SetRangeEnd(D.getName().getSourceRange().getEnd()); } goto PastIdentifier; } } else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { assert(!getLangOpts().CPlusPlus && "There's a C++-specific check for tok::identifier above"); assert(Tok.getIdentifierInfo() && "Not an identifier?"); D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); goto PastIdentifier; } if (Tok.is(tok::l_paren)) { // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' // Example: 'char (*X)' or 'int (*XX)(void)' ParseParenDeclarator(D); // If the declarator was parenthesized, we entered the declarator // scope when parsing the parenthesized declarator, then exited // the scope already. Re-enter the scope, if we need to. if (D.getCXXScopeSpec().isSet()) { // If there was an error parsing parenthesized declarator, declarator // scope may have been entered before. Don't do it again. if (!D.isInvalidType() && Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); } } else if (D.mayOmitIdentifier()) { // This could be something simple like "int" (in which case the declarator // portion is empty), if an abstract-declarator is allowed. D.SetIdentifier(0, Tok.getLocation()); } else { if (D.getContext() == Declarator::MemberContext) Diag(Tok, diag::err_expected_member_name_or_semi) << D.getDeclSpec().getSourceRange(); else if (getLangOpts().CPlusPlus) Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; else Diag(Tok, diag::err_expected_ident_lparen); D.SetIdentifier(0, Tok.getLocation()); D.setInvalidType(true); } PastIdentifier: assert(D.isPastIdentifier() && "Haven't past the location of the identifier yet?"); // Don't parse attributes unless we have parsed an unparenthesized name. if (D.hasName() && !D.getNumTypeObjects()) MaybeParseCXX0XAttributes(D); while (1) { if (Tok.is(tok::l_paren)) { // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); // The paren may be part of a C++ direct initializer, eg. "int x(1);". // In such a case, check if we actually have a function declarator; if it // is not, the declarator has been fully parsed. if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { // When not in file scope, warn for ambiguous function declarators, just // in case the author intended it as a variable definition. bool warnIfAmbiguous = D.getContext() != Declarator::FileContext; if (!isCXXFunctionDeclarator(warnIfAmbiguous)) break; } ParsedAttributes attrs(AttrFactory); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ParseFunctionDeclarator(D, attrs, T); PrototypeScope.Exit(); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); } else { break; } } } /// ParseParenDeclarator - We parsed the declarator D up to a paren. This is /// only called before the identifier, so these are most likely just grouping /// parens for precedence. If we find that these are actually function /// parameter parens in an abstract-declarator, we call ParseFunctionDeclarator. /// /// direct-declarator: /// '(' declarator ')' /// [GNU] '(' attributes declarator ')' /// direct-declarator '(' parameter-type-list ')' /// direct-declarator '(' identifier-list[opt] ')' /// [GNU] direct-declarator '(' parameter-forward-declarations /// parameter-type-list[opt] ')' /// void Parser::ParseParenDeclarator(Declarator &D) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); assert(!D.isPastIdentifier() && "Should be called before passing identifier"); // Eat any attributes before we look at whether this is a grouping or function // declarator paren. If this is a grouping paren, the attribute applies to // the type being built up, for example: // int (__attribute__(()) *x)(long y) // If this ends up not being a grouping paren, the attribute applies to the // first argument, for example: // int (__attribute__(()) int x) // In either case, we need to eat any attributes to be able to determine what // sort of paren this is. // ParsedAttributes attrs(AttrFactory); bool RequiresArg = false; if (Tok.is(tok::kw___attribute)) { ParseGNUAttributes(attrs); // We require that the argument list (if this is a non-grouping paren) be // present even if the attribute list was empty. RequiresArg = true; } // Eat any Microsoft extensions. if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) { ParseMicrosoftTypeAttributes(attrs); } // Eat any Borland extensions. if (Tok.is(tok::kw___pascal)) ParseBorlandTypeAttributes(attrs); // If we haven't past the identifier yet (or where the identifier would be // stored, if this is an abstract declarator), then this is probably just // grouping parens. However, if this could be an abstract-declarator, then // this could also be the start of function arguments (consider 'void()'). bool isGrouping; if (!D.mayOmitIdentifier()) { // If this can't be an abstract-declarator, this *must* be a grouping // paren, because we haven't seen the identifier yet. isGrouping = true; } else if (Tok.is(tok::r_paren) || // 'int()' is a function. (getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || // C++ int(...) isDeclarationSpecifier() || // 'int(int)' is a function. isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function. // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is // considered to be a type, not a K&R identifier-list. isGrouping = false; } else { // Otherwise, this is a grouping paren, e.g. 'int (*X)' or 'int(X)'. isGrouping = true; } // If this is a grouping paren, handle: // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' if (isGrouping) { SourceLocation EllipsisLoc = D.getEllipsisLoc(); D.setEllipsisLoc(SourceLocation()); bool hadGroupingParens = D.hasGroupingParens(); D.setGroupingParens(true); ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. T.consumeClose(); D.AddTypeInfo(DeclaratorChunk::getParen(T.getOpenLocation(), T.getCloseLocation()), attrs, T.getCloseLocation()); D.setGroupingParens(hadGroupingParens); // An ellipsis cannot be placed outside parentheses. if (EllipsisLoc.isValid()) diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); return; } // Okay, if this wasn't a grouping paren, it must be the start of a function // argument list. Recognize that this declarator will never have an // identifier (and remember where it would have been), then call into // ParseFunctionDeclarator to handle of argument list. D.SetIdentifier(0, Tok.getLocation()); // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); ParseFunctionDeclarator(D, attrs, T, RequiresArg); PrototypeScope.Exit(); } /// ParseFunctionDeclarator - We are after the identifier and have parsed the /// declarator D up to a paren, which indicates that we are parsing function /// arguments. /// /// If FirstArgAttrs is non-null, then the caller parsed those arguments /// immediately after the open paren - they should be considered to be the /// first argument of a parameter. /// /// If RequiresArg is true, then the first argument of the function is required /// to be present and required to not be an identifier list. /// /// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt], /// (C++11) ref-qualifier[opt], exception-specification[opt], /// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt]. /// /// [C++11] exception-specification: /// dynamic-exception-specification /// noexcept-specification /// void Parser::ParseFunctionDeclarator(Declarator &D, ParsedAttributes &FirstArgAttrs, BalancedDelimiterTracker &Tracker, bool RequiresArg) { assert(getCurScope()->isFunctionPrototypeScope() && "Should call from a Function scope"); // lparen is already consumed! assert(D.isPastIdentifier() && "Should not call before identifier!"); // This should be true when the function has typed arguments. // Otherwise, it is treated as a K&R-style function. bool HasProto = false; // Build up an array of information about the parsed arguments. SmallVector ParamInfo; // Remember where we see an ellipsis, if any. SourceLocation EllipsisLoc; DeclSpec DS(AttrFactory); bool RefQualifierIsLValueRef = true; SourceLocation RefQualifierLoc; SourceLocation ConstQualifierLoc; SourceLocation VolatileQualifierLoc; ExceptionSpecificationType ESpecType = EST_None; SourceRange ESpecRange; SmallVector DynamicExceptions; SmallVector DynamicExceptionRanges; ExprResult NoexceptExpr; - CachedTokens *ExceptionSpecTokens = 0; ParsedAttributes FnAttrs(AttrFactory); ParsedType TrailingReturnType; Actions.ActOnStartFunctionDeclarator(); SourceLocation EndLoc; if (isFunctionDeclaratorIdentifierList()) { if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); ParseFunctionDeclaratorIdentifierList(D, ParamInfo); Tracker.consumeClose(); EndLoc = Tracker.getCloseLocation(); } else { if (Tok.isNot(tok::r_paren)) ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); HasProto = ParamInfo.size() || getLangOpts().CPlusPlus; // If we have the closing ')', eat it. Tracker.consumeClose(); EndLoc = Tracker.getCloseLocation(); if (getLangOpts().CPlusPlus) { // FIXME: Accept these components in any order, and produce fixits to // correct the order if the user gets it wrong. Ideally we should deal // with the virt-specifier-seq and pure-specifier in the same way. // Parse cv-qualifier-seq[opt]. ParseTypeQualifierListOpt(DS, false /*no attributes*/, false); if (!DS.getSourceRange().getEnd().isInvalid()) { EndLoc = DS.getSourceRange().getEnd(); ConstQualifierLoc = DS.getConstSpecLoc(); VolatileQualifierLoc = DS.getVolatileSpecLoc(); } // Parse ref-qualifier[opt]. if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { Diag(Tok, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_ref_qualifier : diag::ext_ref_qualifier); RefQualifierIsLValueRef = Tok.is(tok::amp); RefQualifierLoc = ConsumeToken(); EndLoc = RefQualifierLoc; } // C++11 [expr.prim.general]p3: // If a declaration declares a member function or member function // template of a class X, the expression this is a prvalue of type // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq // and the end of the function-definition, member-declarator, or // declarator. bool IsCXX11MemberFunction = getLangOpts().CPlusPlus0x && (D.getContext() == Declarator::MemberContext || (D.getContext() == Declarator::FileContext && D.getCXXScopeSpec().isValid() && Actions.CurContext->isRecord())); Sema::CXXThisScopeRAII ThisScope(Actions, dyn_cast(Actions.CurContext), DS.getTypeQualifiers(), IsCXX11MemberFunction); - + // Parse exception-specification[opt]. - bool Delayed = (D.getContext() == Declarator::MemberContext && - D.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_typedef && - !D.getDeclSpec().isFriendSpecified()); - ESpecType = tryParseExceptionSpecification(Delayed, - ESpecRange, + ESpecType = tryParseExceptionSpecification(ESpecRange, DynamicExceptions, DynamicExceptionRanges, - NoexceptExpr, - ExceptionSpecTokens); + NoexceptExpr); if (ESpecType != EST_None) EndLoc = ESpecRange.getEnd(); // Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes // after the exception-specification. MaybeParseCXX0XAttributes(FnAttrs); // Parse trailing-return-type[opt]. if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) { Diag(Tok, diag::warn_cxx98_compat_trailing_return_type); SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range).get(); if (Range.getEnd().isValid()) EndLoc = Range.getEnd(); } } } // Remember that we parsed a function type, and remember the attributes. D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto, /*isVariadic=*/EllipsisLoc.isValid(), EllipsisLoc, ParamInfo.data(), ParamInfo.size(), DS.getTypeQualifiers(), RefQualifierIsLValueRef, RefQualifierLoc, ConstQualifierLoc, VolatileQualifierLoc, /*MutableLoc=*/SourceLocation(), ESpecType, ESpecRange.getBegin(), DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, - ExceptionSpecTokens, Tracker.getOpenLocation(), EndLoc, D, TrailingReturnType), FnAttrs, EndLoc); Actions.ActOnEndFunctionDeclarator(); } /// isFunctionDeclaratorIdentifierList - This parameter list may have an /// identifier list form for a K&R-style function: void foo(a,b,c) /// /// Note that identifier-lists are only allowed for normal declarators, not for /// abstract-declarators. bool Parser::isFunctionDeclaratorIdentifierList() { return !getLangOpts().CPlusPlus && Tok.is(tok::identifier) && !TryAltiVecVectorToken() // K&R identifier lists can't have typedefs as identifiers, per C99 // 6.7.5.3p11. && (TryAnnotateTypeOrScopeToken() || !Tok.is(tok::annot_typename)) // Identifier lists follow a really simple grammar: the identifiers can // be followed *only* by a ", identifier" or ")". However, K&R // identifier lists are really rare in the brave new modern world, and // it is very common for someone to typo a type in a non-K&R style // list. If we are presented with something like: "void foo(intptr x, // float y)", we don't want to start parsing the function declarator as // though it is a K&R style declarator just because intptr is an // invalid type. // // To handle this, we check to see if the token after the first // identifier is a "," or ")". Only then do we parse it as an // identifier list. && (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)); } /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator /// we found a K&R-style identifier list instead of a typed parameter list. /// /// After returning, ParamInfo will hold the parsed parameters. /// /// identifier-list: [C99 6.7.5] /// identifier /// identifier-list ',' identifier /// void Parser::ParseFunctionDeclaratorIdentifierList( Declarator &D, SmallVector &ParamInfo) { // If there was no identifier specified for the declarator, either we are in // an abstract-declarator, or we are in a parameter declarator which was found // to be abstract. In abstract-declarators, identifier lists are not valid: // diagnose this. if (!D.getIdentifier()) Diag(Tok, diag::ext_ident_list_in_param); // Maintain an efficient lookup of params we have seen so far. llvm::SmallSet ParamsSoFar; while (1) { // If this isn't an identifier, report the error and skip until ')'. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true); // Forget we parsed anything. ParamInfo.clear(); return; } IdentifierInfo *ParmII = Tok.getIdentifierInfo(); // Reject 'typedef int y; int test(x, y)', but continue parsing. if (Actions.getTypeName(*ParmII, Tok.getLocation(), getCurScope())) Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII; // Verify that the argument identifier has not already been mentioned. if (!ParamsSoFar.insert(ParmII)) { Diag(Tok, diag::err_param_redefinition) << ParmII; } else { // Remember this identifier in ParamInfo. ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, Tok.getLocation(), 0)); } // Eat the identifier. ConsumeToken(); // The list continues if we see a comma. if (Tok.isNot(tok::comma)) break; ConsumeToken(); } } /// ParseParameterDeclarationClause - Parse a (possibly empty) parameter-list /// after the opening parenthesis. This function will not parse a K&R-style /// identifier list. /// /// D is the declarator being parsed. If FirstArgAttrs is non-null, then the /// caller parsed those arguments immediately after the open paren - they should /// be considered to be part of the first parameter. /// /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will /// be the location of the ellipsis, if any was parsed. /// /// parameter-type-list: [C99 6.7.5] /// parameter-list /// parameter-list ',' '...' /// [C++] parameter-list '...' /// /// parameter-list: [C99 6.7.5] /// parameter-declaration /// parameter-list ',' parameter-declaration /// /// parameter-declaration: [C99 6.7.5] /// declaration-specifiers declarator /// [C++] declaration-specifiers declarator '=' assignment-expression /// [C++11] initializer-clause /// [GNU] declaration-specifiers declarator attributes /// declaration-specifiers abstract-declarator[opt] /// [C++] declaration-specifiers abstract-declarator[opt] /// '=' assignment-expression /// [GNU] declaration-specifiers abstract-declarator[opt] attributes /// [C++11] attribute-specifier-seq parameter-declaration /// void Parser::ParseParameterDeclarationClause( Declarator &D, ParsedAttributes &FirstArgAttrs, SmallVector &ParamInfo, SourceLocation &EllipsisLoc) { while (1) { if (Tok.is(tok::ellipsis)) { // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq // before deciding this was a parameter-declaration-clause. EllipsisLoc = ConsumeToken(); // Consume the ellipsis. break; } // Parse the declaration-specifiers. // Just use the ParsingDeclaration "scope" of the declarator. DeclSpec DS(AttrFactory); // Parse any C++11 attributes. MaybeParseCXX0XAttributes(DS.getAttributes()); // Skip any Microsoft attributes before a param. if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square)) ParseMicrosoftAttributes(DS.getAttributes()); SourceLocation DSStart = Tok.getLocation(); // If the caller parsed attributes for the first argument, add them now. // Take them so that we only apply the attributes to the first parameter. // FIXME: If we can leave the attributes in the token stream somehow, we can // get rid of a parameter (FirstArgAttrs) and this statement. It might be // too much hassle. DS.takeAttributesFrom(FirstArgAttrs); ParseDeclarationSpecifiers(DS); // Parse the declarator. This is "PrototypeContext", because we must // accept either 'declarator' or 'abstract-declarator' here. Declarator ParmDecl(DS, Declarator::PrototypeContext); ParseDeclarator(ParmDecl); // Parse GNU attributes, if present. MaybeParseGNUAttributes(ParmDecl); // Remember this parsed parameter in ParamInfo. IdentifierInfo *ParmII = ParmDecl.getIdentifier(); // DefArgToks is used when the parsing of default arguments needs // to be delayed. CachedTokens *DefArgToks = 0; // If no parameter was specified, verify that *something* was specified, // otherwise we have a missing type and identifier. if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 && ParmDecl.getNumTypeObjects() == 0) { // Completely missing, emit error. Diag(DSStart, diag::err_missing_param); } else { // Otherwise, we have something. Add it and let semantic analysis try // to grok it and add the result to the ParamInfo we are building. // Inform the actions module about the parameter declarator, so it gets // added to the current scope. Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); // Parse the default argument, if any. We parse the default // arguments in all dialects; the semantic analysis in // ActOnParamDefaultArgument will reject the default argument in // C. if (Tok.is(tok::equal)) { SourceLocation EqualLoc = Tok.getLocation(); // Parse the default argument if (D.getContext() == Declarator::MemberContext) { // If we're inside a class definition, cache the tokens // corresponding to the default argument. We'll actually parse // them when we see the end of the class definition. // FIXME: Can we use a smart pointer for Toks? DefArgToks = new CachedTokens; if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) { delete DefArgToks; DefArgToks = 0; Actions.ActOnParamDefaultArgumentError(Param); } else { // Mark the end of the default argument so that we know when to // stop when we parse it later on. Token DefArgEnd; DefArgEnd.startToken(); DefArgEnd.setKind(tok::cxx_defaultarg_end); DefArgEnd.setLocation(Tok.getLocation()); DefArgToks->push_back(DefArgEnd); Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc, (*DefArgToks)[1].getLocation()); } } else { // Consume the '='. ConsumeToken(); // The argument isn't actually potentially evaluated unless it is // used. EnterExpressionEvaluationContext Eval(Actions, Sema::PotentiallyEvaluatedIfUsed, Param); ExprResult DefArgResult; if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); DefArgResult = ParseBraceInitializer(); } else DefArgResult = ParseAssignmentExpression(); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param); SkipUntil(tok::comma, tok::r_paren, true, true); } else { // Inform the actions module about the default argument Actions.ActOnParamDefaultArgument(Param, EqualLoc, DefArgResult.take()); } } } ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, ParmDecl.getIdentifierLoc(), Param, DefArgToks)); } // If the next token is a comma, consume it and keep reading arguments. if (Tok.isNot(tok::comma)) { if (Tok.is(tok::ellipsis)) { EllipsisLoc = ConsumeToken(); // Consume the ellipsis. if (!getLangOpts().CPlusPlus) { // We have ellipsis without a preceding ',', which is ill-formed // in C. Complain and provide the fix. Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis) << FixItHint::CreateInsertion(EllipsisLoc, ", "); } } break; } // Consume the comma. ConsumeToken(); } } /// [C90] direct-declarator '[' constant-expression[opt] ']' /// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' /// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' /// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' /// [C++11] direct-declarator '[' constant-expression[opt] ']' /// attribute-specifier-seq[opt] void Parser::ParseBracketDeclarator(Declarator &D) { if (CheckProhibitedCXX11Attribute()) return; BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); // C array syntax has many features, but by-far the most common is [] and [4]. // This code does a fast path to handle some of the most obvious cases. if (Tok.getKind() == tok::r_square) { T.consumeClose(); ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed the empty array type. ExprResult NumElements; D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, T.getOpenLocation(), T.getCloseLocation()), attrs, T.getCloseLocation()); return; } else if (Tok.getKind() == tok::numeric_constant && GetLookAheadToken(1).is(tok::r_square)) { // [4] is very common. Parse the numeric constant expression. ExprResult ExprRes(Actions.ActOnNumericConstant(Tok, getCurScope())); ConsumeToken(); T.consumeClose(); ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0, ExprRes.release(), T.getOpenLocation(), T.getCloseLocation()), attrs, T.getCloseLocation()); return; } // If valid, this location is the position where we read the 'static' keyword. SourceLocation StaticLoc; if (Tok.is(tok::kw_static)) StaticLoc = ConsumeToken(); // If there is a type-qualifier-list, read it now. // Type qualifiers in an array subscript are a C99 feature. DeclSpec DS(AttrFactory); ParseTypeQualifierListOpt(DS, false /*no attributes*/); // If we haven't already read 'static', check to see if there is one after the // type-qualifier-list. if (!StaticLoc.isValid() && Tok.is(tok::kw_static)) StaticLoc = ConsumeToken(); // Handle "direct-declarator [ type-qual-list[opt] * ]". bool isStar = false; ExprResult NumElements; // Handle the case where we have '[*]' as the array size. However, a leading // star could be the start of an expression, for example 'X[*p + 4]'. Verify // the the token after the star is a ']'. Since stars in arrays are // infrequent, use of lookahead is not costly here. if (Tok.is(tok::star) && GetLookAheadToken(1).is(tok::r_square)) { ConsumeToken(); // Eat the '*'. if (StaticLoc.isValid()) { Diag(StaticLoc, diag::err_unspecified_vla_size_with_static); StaticLoc = SourceLocation(); // Drop the static. } isStar = true; } else if (Tok.isNot(tok::r_square)) { // Note, in C89, this production uses the constant-expr production instead // of assignment-expr. The only difference is that assignment-expr allows // things like '=' and '*='. Sema rejects these in C89 mode because they // are not i-c-e's, so we don't need to distinguish between the two here. // Parse the constant-expression or assignment-expression now (depending // on dialect). if (getLangOpts().CPlusPlus) { NumElements = ParseConstantExpression(); } else { EnterExpressionEvaluationContext Unevaluated(Actions, Sema::ConstantEvaluated); NumElements = ParseAssignmentExpression(); } } // If there was an error parsing the assignment-expression, recover. if (NumElements.isInvalid()) { D.setInvalidType(true); // If the expression was invalid, skip it. SkipUntil(tok::r_square); return; } T.consumeClose(); ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), StaticLoc.isValid(), isStar, NumElements.release(), T.getOpenLocation(), T.getCloseLocation()), attrs, T.getCloseLocation()); } /// [GNU] typeof-specifier: /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// void Parser::ParseTypeofSpecifier(DeclSpec &DS) { assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier"); Token OpTok = Tok; SourceLocation StartLoc = ConsumeToken(); const bool hasParens = Tok.is(tok::l_paren); EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); bool isCastExpr; ParsedType CastTy; SourceRange CastRange; ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange); if (hasParens) DS.setTypeofParensRange(CastRange); if (CastRange.getEnd().isInvalid()) // FIXME: Not accurate, the range gets one token more than it should. DS.SetRangeEnd(Tok.getLocation()); else DS.SetRangeEnd(CastRange.getEnd()); if (isCastExpr) { if (!CastTy) { DS.SetTypeSpecError(); return; } const char *PrevSpec = 0; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec, DiagID, CastTy)) Diag(StartLoc, DiagID) << PrevSpec; return; } // If we get here, the operand to the typeof was an expresion. if (Operand.isInvalid()) { DS.SetTypeSpecError(); return; } // We might need to transform the operand if it is potentially evaluated. Operand = Actions.HandleExprEvaluationContextForTypeof(Operand.get()); if (Operand.isInvalid()) { DS.SetTypeSpecError(); return; } const char *PrevSpec = 0; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, DiagID, Operand.get())) Diag(StartLoc, DiagID) << PrevSpec; } /// [C11] atomic-specifier: /// _Atomic ( type-name ) /// void Parser::ParseAtomicSpecifier(DeclSpec &DS) { assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier"); SourceLocation StartLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen_after, "_Atomic")) { SkipUntil(tok::r_paren); return; } TypeResult Result = ParseTypeName(); if (Result.isInvalid()) { SkipUntil(tok::r_paren); return; } // Match the ')' T.consumeClose(); if (T.getCloseLocation().isInvalid()) return; DS.setTypeofParensRange(T.getRange()); DS.SetRangeEnd(T.getCloseLocation()); const char *PrevSpec = 0; unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec, DiagID, Result.release())) Diag(StartLoc, DiagID) << PrevSpec; } /// TryAltiVecVectorTokenOutOfLine - Out of line body that should only be called /// from TryAltiVecVectorToken. bool Parser::TryAltiVecVectorTokenOutOfLine() { Token Next = NextToken(); switch (Next.getKind()) { default: return false; case tok::kw_short: case tok::kw_long: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_void: case tok::kw_char: case tok::kw_int: case tok::kw_float: case tok::kw_double: case tok::kw_bool: case tok::kw___pixel: Tok.setKind(tok::kw___vector); return true; case tok::identifier: if (Next.getIdentifierInfo() == Ident_pixel) { Tok.setKind(tok::kw___vector); return true; } return false; } } bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, bool &isInvalid) { if (Tok.getIdentifierInfo() == Ident_vector) { Token Next = NextToken(); switch (Next.getKind()) { case tok::kw_short: case tok::kw_long: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_void: case tok::kw_char: case tok::kw_int: case tok::kw_float: case tok::kw_double: case tok::kw_bool: case tok::kw___pixel: isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); return true; case tok::identifier: if (Next.getIdentifierInfo() == Ident_pixel) { isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); return true; } break; default: break; } } else if ((Tok.getIdentifierInfo() == Ident_pixel) && DS.isTypeAltiVecVector()) { isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); return true; } return false; } Index: vendor/clang/dist/lib/Parse/ParseDeclCXX.cpp =================================================================== --- vendor/clang/dist/lib/Parse/ParseDeclCXX.cpp (revision 235808) +++ vendor/clang/dist/lib/Parse/ParseDeclCXX.cpp (revision 235809) @@ -1,3084 +1,3020 @@ //===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===// // // 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 C++ Declaration portions of the Parser interfaces. // //===----------------------------------------------------------------------===// #include "clang/Basic/OperatorKinds.h" #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "llvm/ADT/SmallString.h" #include "RAIIObjectsForParser.h" using namespace clang; /// ParseNamespace - We know that the current token is a namespace keyword. This /// may either be a top level namespace or a block-level namespace alias. If /// there was an inline keyword, it has already been parsed. /// /// namespace-definition: [C++ 7.3: basic.namespace] /// named-namespace-definition /// unnamed-namespace-definition /// /// unnamed-namespace-definition: /// 'inline'[opt] 'namespace' attributes[opt] '{' namespace-body '}' /// /// named-namespace-definition: /// original-namespace-definition /// extension-namespace-definition /// /// original-namespace-definition: /// 'inline'[opt] 'namespace' identifier attributes[opt] /// '{' namespace-body '}' /// /// extension-namespace-definition: /// 'inline'[opt] 'namespace' original-namespace-name /// '{' namespace-body '}' /// /// namespace-alias-definition: [C++ 7.3.2: namespace.alias] /// 'namespace' identifier '=' qualified-namespace-specifier ';' /// Decl *Parser::ParseNamespace(unsigned Context, SourceLocation &DeclEnd, SourceLocation InlineLoc) { assert(Tok.is(tok::kw_namespace) && "Not a namespace!"); SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'. ObjCDeclContextSwitch ObjCDC(*this); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteNamespaceDecl(getCurScope()); cutOffParsing(); return 0; } SourceLocation IdentLoc; IdentifierInfo *Ident = 0; std::vector ExtraIdentLoc; std::vector ExtraIdent; std::vector ExtraNamespaceLoc; Token attrTok; if (Tok.is(tok::identifier)) { Ident = Tok.getIdentifierInfo(); IdentLoc = ConsumeToken(); // eat the identifier. while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) { ExtraNamespaceLoc.push_back(ConsumeToken()); ExtraIdent.push_back(Tok.getIdentifierInfo()); ExtraIdentLoc.push_back(ConsumeToken()); } } // Read label attributes, if present. ParsedAttributes attrs(AttrFactory); if (Tok.is(tok::kw___attribute)) { attrTok = Tok; ParseGNUAttributes(attrs); } if (Tok.is(tok::equal)) { if (!attrs.empty()) Diag(attrTok, diag::err_unexpected_namespace_attributes_alias); if (InlineLoc.isValid()) Diag(InlineLoc, diag::err_inline_namespace_alias) << FixItHint::CreateRemoval(InlineLoc); return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd); } BalancedDelimiterTracker T(*this, tok::l_brace); if (T.consumeOpen()) { if (!ExtraIdent.empty()) { Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); } Diag(Tok, Ident ? diag::err_expected_lbrace : diag::err_expected_ident_lbrace); return 0; } if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() || getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() || getCurScope()->getFnParent()) { if (!ExtraIdent.empty()) { Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); } Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope); SkipUntil(tok::r_brace, false); return 0; } if (!ExtraIdent.empty()) { TentativeParsingAction TPA(*this); SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true); Token rBraceToken = Tok; TPA.Revert(); if (!rBraceToken.is(tok::r_brace)) { Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); } else { std::string NamespaceFix; for (std::vector::iterator I = ExtraIdent.begin(), E = ExtraIdent.end(); I != E; ++I) { NamespaceFix += " { namespace "; NamespaceFix += (*I)->getName(); } std::string RBraces; for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i) RBraces += "} "; Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()), NamespaceFix) << FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces); } } // If we're still good, complain about inline namespaces in non-C++0x now. if (InlineLoc.isValid()) Diag(InlineLoc, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace); // Enter a scope for the namespace. ParseScope NamespaceScope(this, Scope::DeclScope); Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, NamespaceLoc, IdentLoc, Ident, T.getOpenLocation(), attrs.getList()); PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, "parsing namespace"); // Parse the contents of the namespace. This includes parsing recovery on // any improperly nested namespaces. ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0, InlineLoc, attrs, T); // Leave the namespace scope. NamespaceScope.Exit(); DeclEnd = T.getCloseLocation(); Actions.ActOnFinishNamespaceDef(NamespcDecl, DeclEnd); return NamespcDecl; } /// ParseInnerNamespace - Parse the contents of a namespace. void Parser::ParseInnerNamespace(std::vector& IdentLoc, std::vector& Ident, std::vector& NamespaceLoc, unsigned int index, SourceLocation& InlineLoc, ParsedAttributes& attrs, BalancedDelimiterTracker &Tracker) { if (index == Ident.size()) { while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); } // The caller is what called check -- we are simply calling // the close for it. Tracker.consumeClose(); return; } // Parse improperly nested namespaces. ParseScope NamespaceScope(this, Scope::DeclScope); Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(), NamespaceLoc[index], IdentLoc[index], Ident[index], Tracker.getOpenLocation(), attrs.getList()); ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc, attrs, Tracker); NamespaceScope.Exit(); Actions.ActOnFinishNamespaceDef(NamespcDecl, Tracker.getCloseLocation()); } /// ParseNamespaceAlias - Parse the part after the '=' in a namespace /// alias definition. /// Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, SourceLocation &DeclEnd) { assert(Tok.is(tok::equal) && "Not equal token"); ConsumeToken(); // eat the '='. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteNamespaceAliasDecl(getCurScope()); cutOffParsing(); return 0; } CXXScopeSpec SS; // Parse (optional) nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); if (SS.isInvalid() || Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_namespace_name); // Skip to end of the definition and eat the ';'. SkipUntil(tok::semi); return 0; } // Parse identifier. IdentifierInfo *Ident = Tok.getIdentifierInfo(); SourceLocation IdentLoc = ConsumeToken(); // Eat the ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name, "", tok::semi); return Actions.ActOnNamespaceAliasDef(getCurScope(), NamespaceLoc, AliasLoc, Alias, SS, IdentLoc, Ident); } /// ParseLinkage - We know that the current token is a string_literal /// and just before that, that extern was seen. /// /// linkage-specification: [C++ 7.5p2: dcl.link] /// 'extern' string-literal '{' declaration-seq[opt] '}' /// 'extern' string-literal declaration /// Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { assert(Tok.is(tok::string_literal) && "Not a string literal!"); SmallString<8> LangBuffer; bool Invalid = false; StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); if (Invalid) return 0; // FIXME: This is incorrect: linkage-specifiers are parsed in translation // phase 7, so string-literal concatenation is supposed to occur. // extern "" "C" "" "+" "+" { } is legal. if (Tok.hasUDSuffix()) Diag(Tok, diag::err_invalid_string_udl); SourceLocation Loc = ConsumeStringToken(); ParseScope LinkageScope(this, Scope::DeclScope); Decl *LinkageSpec = Actions.ActOnStartLinkageSpecification(getCurScope(), DS.getSourceRange().getBegin(), Loc, Lang, Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation()); ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); if (Tok.isNot(tok::l_brace)) { // Reset the source range in DS, as the leading "extern" // does not really belong to the inner declaration ... DS.SetRangeStart(SourceLocation()); DS.SetRangeEnd(SourceLocation()); // ... but anyway remember that such an "extern" was seen. DS.setExternInLinkageSpec(true); ParseExternalDeclaration(attrs, &DS); return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, SourceLocation()); } DS.abort(); ProhibitAttributes(attrs); BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); } T.consumeClose(); return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, T.getCloseLocation()); } /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or /// using-directive. Assumes that current token is 'using'. Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd, ParsedAttributesWithRange &attrs, Decl **OwnedType) { assert(Tok.is(tok::kw_using) && "Not using token"); ObjCDeclContextSwitch ObjCDC(*this); // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteUsing(getCurScope()); cutOffParsing(); return 0; } // 'using namespace' means this is a using-directive. if (Tok.is(tok::kw_namespace)) { // Template parameters are always an error here. if (TemplateInfo.Kind) { SourceRange R = TemplateInfo.getSourceRange(); Diag(UsingLoc, diag::err_templated_using_directive) << R << FixItHint::CreateRemoval(R); } return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs); } // Otherwise, it must be a using-declaration or an alias-declaration. // Using declarations can't have attributes. ProhibitAttributes(attrs); return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd, AS_none, OwnedType); } /// ParseUsingDirective - Parse C++ using-directive, assumes /// that current token is 'namespace' and 'using' was already parsed. /// /// using-directive: [C++ 7.3.p4: namespace.udir] /// 'using' 'namespace' ::[opt] nested-name-specifier[opt] /// namespace-name ; /// [GNU] using-directive: /// 'using' 'namespace' ::[opt] nested-name-specifier[opt] /// namespace-name attributes[opt] ; /// Decl *Parser::ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, ParsedAttributes &attrs) { assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token"); // Eat 'namespace'. SourceLocation NamespcLoc = ConsumeToken(); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteUsingDirective(getCurScope()); cutOffParsing(); return 0; } CXXScopeSpec SS; // Parse (optional) nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); IdentifierInfo *NamespcName = 0; SourceLocation IdentLoc = SourceLocation(); // Parse namespace-name. if (SS.isInvalid() || Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_namespace_name); // If there was invalid namespace name, skip to end of decl, and eat ';'. SkipUntil(tok::semi); // FIXME: Are there cases, when we would like to call ActOnUsingDirective? return 0; } // Parse identifier. NamespcName = Tok.getIdentifierInfo(); IdentLoc = ConsumeToken(); // Parse (optional) attributes (most likely GNU strong-using extension). bool GNUAttr = false; if (Tok.is(tok::kw___attribute)) { GNUAttr = true; ParseGNUAttributes(attrs); } // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, GNUAttr ? diag::err_expected_semi_after_attribute_list : diag::err_expected_semi_after_namespace_name, "", tok::semi); return Actions.ActOnUsingDirective(getCurScope(), UsingLoc, NamespcLoc, SS, IdentLoc, NamespcName, attrs.getList()); } /// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration. /// Assumes that 'using' was already seen. /// /// using-declaration: [C++ 7.3.p3: namespace.udecl] /// 'using' 'typename'[opt] ::[opt] nested-name-specifier /// unqualified-id /// 'using' :: unqualified-id /// /// alias-declaration: C++0x [decl.typedef]p2 /// 'using' identifier = type-id ; /// Decl *Parser::ParseUsingDeclaration(unsigned Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, SourceLocation &DeclEnd, AccessSpecifier AS, Decl **OwnedType) { CXXScopeSpec SS; SourceLocation TypenameLoc; bool IsTypeName; // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { TypenameLoc = Tok.getLocation(); ConsumeToken(); IsTypeName = true; } else IsTypeName = false; // Parse nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); // Check nested-name specifier. if (SS.isInvalid()) { SkipUntil(tok::semi); return 0; } // Parse the unqualified-id. We allow parsing of both constructor and // destructor names and allow the action module to diagnose any semantic // errors. SourceLocation TemplateKWLoc; UnqualifiedId Name; if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/true, /*AllowConstructorName=*/true, ParsedType(), TemplateKWLoc, Name)) { SkipUntil(tok::semi); return 0; } ParsedAttributes attrs(AttrFactory); // Maybe this is an alias-declaration. bool IsAliasDecl = Tok.is(tok::equal); TypeResult TypeAlias; if (IsAliasDecl) { // TODO: Attribute support. C++0x attributes may appear before the equals. // Where can GNU attributes appear? ConsumeToken(); Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_alias_declaration : diag::ext_alias_declaration); // Type alias templates cannot be specialized. int SpecKind = -1; if (TemplateInfo.Kind == ParsedTemplateInfo::Template && Name.getKind() == UnqualifiedId::IK_TemplateId) SpecKind = 0; if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) SpecKind = 1; if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) SpecKind = 2; if (SpecKind != -1) { SourceRange Range; if (SpecKind == 0) Range = SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc); else Range = TemplateInfo.getSourceRange(); Diag(Range.getBegin(), diag::err_alias_declaration_specialization) << SpecKind << Range; SkipUntil(tok::semi); return 0; } // Name must be an identifier. if (Name.getKind() != UnqualifiedId::IK_Identifier) { Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier); // No removal fixit: can't recover from this. SkipUntil(tok::semi); return 0; } else if (IsTypeName) Diag(TypenameLoc, diag::err_alias_declaration_not_identifier) << FixItHint::CreateRemoval(SourceRange(TypenameLoc, SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc)); else if (SS.isNotEmpty()) Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) << FixItHint::CreateRemoval(SS.getRange()); TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? Declarator::AliasTemplateContext : Declarator::AliasDeclContext, AS, OwnedType); } else // Parse (optional) attributes (most likely GNU strong-using extension). MaybeParseGNUAttributes(attrs); // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, !attrs.empty() ? "attributes list" : IsAliasDecl ? "alias declaration" : "using declaration", tok::semi); // Diagnose an attempt to declare a templated using-declaration. // In C++0x, alias-declarations can be templates: // template <...> using id = type; if (TemplateInfo.Kind && !IsAliasDecl) { SourceRange R = TemplateInfo.getSourceRange(); Diag(UsingLoc, diag::err_templated_using_declaration) << R << FixItHint::CreateRemoval(R); // Unfortunately, we have to bail out instead of recovering by // ignoring the parameters, just in case the nested name specifier // depends on the parameters. return 0; } // "typename" keyword is allowed for identifiers only, // because it may be a type definition. if (IsTypeName && Name.getKind() != UnqualifiedId::IK_Identifier) { Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only) << FixItHint::CreateRemoval(SourceRange(TypenameLoc)); // Proceed parsing, but reset the IsTypeName flag. IsTypeName = false; } if (IsAliasDecl) { TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; MultiTemplateParamsArg TemplateParamsArg(Actions, TemplateParams ? TemplateParams->data() : 0, TemplateParams ? TemplateParams->size() : 0); return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, UsingLoc, Name, TypeAlias); } return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, Name, attrs.getList(), IsTypeName, TypenameLoc); } /// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration. /// /// [C++0x] static_assert-declaration: /// static_assert ( constant-expression , string-literal ) ; /// /// [C11] static_assert-declaration: /// _Static_assert ( constant-expression , string-literal ) ; /// Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) && "Not a static_assert declaration"); if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11) Diag(Tok, diag::ext_c11_static_assert); if (Tok.is(tok::kw_static_assert)) Diag(Tok, diag::warn_cxx98_compat_static_assert); SourceLocation StaticAssertLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen); return 0; } ExprResult AssertExpr(ParseConstantExpression()); if (AssertExpr.isInvalid()) { SkipUntil(tok::semi); return 0; } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi)) return 0; if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal); SkipUntil(tok::semi); return 0; } ExprResult AssertMessage(ParseStringLiteralExpression()); if (AssertMessage.isInvalid()) { SkipUntil(tok::semi); return 0; } T.consumeClose(); DeclEnd = Tok.getLocation(); ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert); return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, AssertExpr.take(), AssertMessage.take(), T.getCloseLocation()); } /// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. /// /// 'decltype' ( expression ) /// SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) && "Not a decltype specifier"); ExprResult Result; SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc; if (Tok.is(tok::annot_decltype)) { Result = getExprAnnotation(Tok); EndLoc = Tok.getAnnotationEndLoc(); ConsumeToken(); if (Result.isInvalid()) { DS.SetTypeSpecError(); return EndLoc; } } else { if (Tok.getIdentifierInfo()->isStr("decltype")) Diag(Tok, diag::warn_cxx98_compat_decltype); ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen_after, "decltype", tok::r_paren)) { DS.SetTypeSpecError(); return T.getOpenLocation() == Tok.getLocation() ? StartLoc : T.getOpenLocation(); } // Parse the expression // C++0x [dcl.type.simple]p4: // The operand of the decltype specifier is an unevaluated operand. EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, 0, /*IsDecltype=*/true); Result = ParseExpression(); if (Result.isInvalid()) { SkipUntil(tok::r_paren); DS.SetTypeSpecError(); return StartLoc; } // Match the ')' T.consumeClose(); if (T.getCloseLocation().isInvalid()) { DS.SetTypeSpecError(); // FIXME: this should return the location of the last token // that was consumed (by "consumeClose()") return T.getCloseLocation(); } Result = Actions.ActOnDecltypeExpression(Result.take()); if (Result.isInvalid()) { DS.SetTypeSpecError(); return T.getCloseLocation(); } EndLoc = T.getCloseLocation(); } const char *PrevSpec = 0; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int decltype(a)"). if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, DiagID, Result.release())) { Diag(StartLoc, DiagID) << PrevSpec; DS.SetTypeSpecError(); } return EndLoc; } void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS, SourceLocation StartLoc, SourceLocation EndLoc) { // make sure we have a token we can turn into an annotation token if (PP.isBacktrackEnabled()) PP.RevertCachedTokens(1); else PP.EnterToken(Tok); Tok.setKind(tok::annot_decltype); setExprAnnotation(Tok, DS.getTypeSpecType() == TST_decltype ? DS.getRepAsExpr() : ExprResult()); Tok.setAnnotationEndLoc(EndLoc); Tok.setLocation(StartLoc); PP.AnnotateCachedTokens(Tok); } void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { assert(Tok.is(tok::kw___underlying_type) && "Not an underlying type specifier"); SourceLocation StartLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen_after, "__underlying_type", tok::r_paren)) { return; } TypeResult Result = ParseTypeName(); if (Result.isInvalid()) { SkipUntil(tok::r_paren); return; } // Match the ')' T.consumeClose(); if (T.getCloseLocation().isInvalid()) return; const char *PrevSpec = 0; unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec, DiagID, Result.release())) Diag(StartLoc, DiagID) << PrevSpec; } /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a /// class name or decltype-specifier. Note that we only check that the result /// names a type; semantic analysis will need to verify that the type names a /// class. The result is either a type or null, depending on whether a type /// name was found. /// /// base-type-specifier: [C++ 10.1] /// class-or-decltype /// class-or-decltype: [C++ 10.1] /// nested-name-specifier[opt] class-name /// decltype-specifier /// class-name: [C++ 9.1] /// identifier /// simple-template-id /// Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, SourceLocation &EndLocation) { // Ignore attempts to use typename if (Tok.is(tok::kw_typename)) { Diag(Tok, diag::err_expected_class_name_not_template) << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); } // Parse optional nested-name-specifier CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); BaseLoc = Tok.getLocation(); // Parse decltype-specifier // tok == kw_decltype is just error recovery, it can only happen when SS // isn't empty if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) { if (SS.isNotEmpty()) Diag(SS.getBeginLoc(), diag::err_unexpected_scope_on_base_decltype) << FixItHint::CreateRemoval(SS.getRange()); // Fake up a Declarator to use with ActOnTypeName. DeclSpec DS(AttrFactory); EndLocation = ParseDecltypeSpecifier(DS); Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); ParsedType Type = getTypeAnnotation(Tok); EndLocation = Tok.getAnnotationEndLoc(); ConsumeToken(); if (Type) return Type; return true; } // Fall through to produce an error below. } if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_class_name); return true; } IdentifierInfo *Id = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); if (Tok.is(tok::less)) { // It looks the user intended to write a template-id here, but the // template-name was wrong. Try to fix that. TemplateNameKind TNK = TNK_Type_template; TemplateTy Template; if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, getCurScope(), &SS, Template, TNK)) { Diag(IdLoc, diag::err_unknown_template_name) << Id; } if (!Template) return true; // Form the template name UnqualifiedId TemplateName; TemplateName.setIdentifier(Id, IdLoc); // Parse the full template-id, then turn it into a type. if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), TemplateName, true)) return true; if (TNK == TNK_Dependent_template_name) AnnotateTemplateIdTokenAsType(); // If we didn't end up with a typename token, there's nothing more we // can do. if (Tok.isNot(tok::annot_typename)) return true; // Retrieve the type from the annotation token, consume that token, and // return. EndLocation = Tok.getAnnotationEndLoc(); ParsedType Type = getTypeAnnotation(Tok); ConsumeToken(); return Type; } // We have an identifier; check whether it is actually a type. ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, false, ParsedType(), /*IsCtorOrDtorName=*/false, /*NonTrivialTypeSourceInfo=*/true); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; } // Consume the identifier. EndLocation = IdLoc; // Fake up a Declarator to use with ActOnTypeName. DeclSpec DS(AttrFactory); DS.SetRangeStart(IdLoc); DS.SetRangeEnd(EndLocation); DS.getTypeSpecScope() = SS; const char *PrevSpec = 0; unsigned DiagID; DS.SetTypeSpecType(TST_typename, IdLoc, PrevSpec, DiagID, Type); Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which /// until we reach the start of a definition or see a token that /// cannot start a definition. /// /// class-specifier: [C++ class] /// class-head '{' member-specification[opt] '}' /// class-head '{' member-specification[opt] '}' attributes[opt] /// class-head: /// class-key identifier[opt] base-clause[opt] /// class-key nested-name-specifier identifier base-clause[opt] /// class-key nested-name-specifier[opt] simple-template-id /// base-clause[opt] /// [GNU] class-key attributes[opt] identifier[opt] base-clause[opt] /// [GNU] class-key attributes[opt] nested-name-specifier /// identifier base-clause[opt] /// [GNU] class-key attributes[opt] nested-name-specifier[opt] /// simple-template-id base-clause[opt] /// class-key: /// 'class' /// 'struct' /// 'union' /// /// elaborated-type-specifier: [C++ dcl.type.elab] /// class-key ::[opt] nested-name-specifier[opt] identifier /// class-key ::[opt] nested-name-specifier[opt] 'template'[opt] /// simple-template-id /// /// Note that the C++ class-specifier and elaborated-type-specifier, /// together, subsume the C99 struct-or-union-specifier: /// /// struct-or-union-specifier: [C99 6.7.2.1] /// struct-or-union identifier[opt] '{' struct-contents '}' /// struct-or-union identifier /// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents /// '}' attributes[opt] /// [GNU] struct-or-union attributes[opt] identifier /// struct-or-union: /// 'struct' /// 'union' void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation StartLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, bool EnteringContext, DeclSpecContext DSC) { DeclSpec::TST TagType; if (TagTokKind == tok::kw_struct) TagType = DeclSpec::TST_struct; else if (TagTokKind == tok::kw_class) TagType = DeclSpec::TST_class; else { assert(TagTokKind == tok::kw_union && "Not a class specifier"); TagType = DeclSpec::TST_union; } if (Tok.is(tok::code_completion)) { // Code completion for a struct, class, or union name. Actions.CodeCompleteTag(getCurScope(), TagType); return cutOffParsing(); } // C++03 [temp.explicit] 14.7.2/8: // The usual access checking rules do not apply to names used to specify // explicit instantiations. // // As an extension we do not perform access checking on the names used to // specify explicit specializations either. This is important to allow // specializing traits classes for private types. Sema::SuppressAccessChecksRAII SuppressAccess(Actions, TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); ParsedAttributes attrs(AttrFactory); // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) ParseGNUAttributes(attrs); // If declspecs exist after tag, parse them. while (Tok.is(tok::kw___declspec)) ParseMicrosoftDeclSpec(attrs); // If C++0x attributes exist here, parse them. // FIXME: Are we consistent with the ordering of parsing of different // styles of attributes? MaybeParseCXX0XAttributes(attrs); if (TagType == DeclSpec::TST_struct && !Tok.is(tok::identifier) && Tok.getIdentifierInfo() && (Tok.is(tok::kw___is_arithmetic) || Tok.is(tok::kw___is_convertible) || Tok.is(tok::kw___is_empty) || Tok.is(tok::kw___is_floating_point) || Tok.is(tok::kw___is_function) || Tok.is(tok::kw___is_fundamental) || Tok.is(tok::kw___is_integral) || Tok.is(tok::kw___is_member_function_pointer) || Tok.is(tok::kw___is_member_pointer) || Tok.is(tok::kw___is_pod) || Tok.is(tok::kw___is_pointer) || Tok.is(tok::kw___is_same) || Tok.is(tok::kw___is_scalar) || Tok.is(tok::kw___is_signed) || Tok.is(tok::kw___is_unsigned) || Tok.is(tok::kw___is_void))) { // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the // name of struct templates, but some are keywords in GCC >= 4.3 // and Clang. Therefore, when we see the token sequence "struct // X", make X into a normal identifier rather than a keyword, to // allow libstdc++ 4.2 and libc++ to work properly. Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); Tok.setKind(tok::identifier); } // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); if (getLangOpts().CPlusPlus) { // "FOO : BAR" is not a potential typo for "FOO::BAR". ColonProtectionRAIIObject X(*this); if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) DS.SetTypeSpecError(); if (SS.isSet()) if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) Diag(Tok, diag::err_expected_ident); } TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; // Parse the (optional) class name or simple-template-id. IdentifierInfo *Name = 0; SourceLocation NameLoc; TemplateIdAnnotation *TemplateId = 0; if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); if (Tok.is(tok::less) && getLangOpts().CPlusPlus) { // The name was supposed to refer to a template, but didn't. // Eat the template argument list and try to continue parsing this as // a class (or template thereof). TemplateArgList TemplateArgs; SourceLocation LAngleLoc, RAngleLoc; if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) { // We couldn't parse the template argument list at all, so don't // try to give any location information for the list. LAngleLoc = RAngleLoc = SourceLocation(); } Diag(NameLoc, diag::err_explicit_spec_non_template) << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) << (TagType == DeclSpec::TST_class? 0 : TagType == DeclSpec::TST_struct? 1 : 2) << Name << SourceRange(LAngleLoc, RAngleLoc); // Strip off the last template parameter list if it was empty, since // we've removed its template argument list. if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { if (TemplateParams && TemplateParams->size() > 1) { TemplateParams->pop_back(); } else { TemplateParams = 0; const_cast(TemplateInfo).Kind = ParsedTemplateInfo::NonTemplate; } } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { // Pretend this is just a forward declaration. TemplateParams = 0; const_cast(TemplateInfo).Kind = ParsedTemplateInfo::NonTemplate; const_cast(TemplateInfo).TemplateLoc = SourceLocation(); const_cast(TemplateInfo).ExternLoc = SourceLocation(); } } } else if (Tok.is(tok::annot_template_id)) { TemplateId = takeTemplateIdAnnotation(Tok); NameLoc = ConsumeToken(); if (TemplateId->Kind != TNK_Type_template && TemplateId->Kind != TNK_Dependent_template_name) { // The template-name in the simple-template-id refers to // something other than a class template. Give an appropriate // error message and skip to the ';'. SourceRange Range(NameLoc); if (SS.isNotEmpty()) Range.setBegin(SS.getBeginLoc()); Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template) << Name << static_cast(TemplateId->Kind) << Range; DS.SetTypeSpecError(); SkipUntil(tok::semi, false, true); return; } } // As soon as we're finished parsing the class's template-id, turn access // checking back on. SuppressAccess.done(); // There are four options here. // - If we are in a trailing return type, this is always just a reference, // and we must not try to parse a definition. For instance, // [] () -> struct S { }; // does not define a type. // - If we have 'struct foo {...', 'struct foo :...', // 'struct foo final :' or 'struct foo final {', then this is a definition. // - If we have 'struct foo;', then this is either a forward declaration // or a friend declaration, which have to be treated differently. // - Otherwise we have something like 'struct foo xyz', a reference. // However, in type-specifier-seq's, things look like declarations but are // just references, e.g. // new struct s; // or // &T::operator struct s; // For these, DSC is DSC_type_specifier. Sema::TagUseKind TUK; if (DSC == DSC_trailing) TUK = Sema::TUK_Reference; else if (Tok.is(tok::l_brace) || (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || (isCXX0XFinalKeyword() && (NextToken().is(tok::l_brace) || NextToken().is(tok::colon)))) { if (DS.isFriendSpecified()) { // C++ [class.friend]p2: // A class shall not be defined in a friend declaration. Diag(Tok.getLocation(), diag::err_friend_decl_defines_type) << SourceRange(DS.getFriendSpecLoc()); // Skip everything up to the semicolon, so that this looks like a proper // friend class (or template thereof) declaration. SkipUntil(tok::semi, true, true); TUK = Sema::TUK_Friend; } else { // Okay, this is a class definition. TUK = Sema::TUK_Definition; } } else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; else TUK = Sema::TUK_Reference; if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error || TUK != Sema::TUK_Definition)) { if (DS.getTypeSpecType() != DeclSpec::TST_error) { // We have a declaration or reference to an anonymous class. Diag(StartLoc, diag::err_anon_type_definition) << DeclSpec::getSpecifierName(TagType); } SkipUntil(tok::comma, true); return; } // Create the tag portion of the class or class template. DeclResult TagOrTempResult = true; // invalid TypeResult TypeResult = true; // invalid bool Owned = false; if (TemplateId) { // Explicit specialization, class template partial specialization, // or explicit instantiation. ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), TemplateId->NumArgs); if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { // This is an explicit instantiation of a class template. TagOrTempResult = Actions.ActOnExplicitInstantiation(getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, TagType, StartLoc, SS, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, attrs.getList()); // Friend template-ids are treated as references unless // they have template headers, in which case they're ill-formed // (FIXME: "template friend class A::B;"). // We diagnose this error in ActOnClassTemplateSpecialization. } else if (TUK == Sema::TUK_Reference || (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc, TemplateId->SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc); } else { // This is an explicit specialization or a class template // partial specialization. TemplateParameterLists FakedParamLists; if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { // This looks like an explicit instantiation, because we have // something like // // template class Foo // // but it actually has a definition. Most likely, this was // meant to be an explicit specialization, but the user forgot // the '<>' after 'template'. assert(TUK == Sema::TUK_Definition && "Expected a definition here"); SourceLocation LAngleLoc = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); Diag(TemplateId->TemplateNameLoc, diag::err_explicit_instantiation_with_definition) << SourceRange(TemplateInfo.TemplateLoc) << FixItHint::CreateInsertion(LAngleLoc, "<>"); // Create a fake template parameter list that contains only // "template<>", so that we treat this construct as a class // template specialization. FakedParamLists.push_back( Actions.ActOnTemplateParameterList(0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, LAngleLoc)); TemplateParams = &FakedParamLists; } // Build the class template specialization. TagOrTempResult = Actions.ActOnClassTemplateSpecialization(getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(), SS, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, attrs.getList(), MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); } } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { // Explicit instantiation of a member of a class template // specialization, e.g., // // template struct Outer::Inner; // TagOrTempResult = Actions.ActOnExplicitInstantiation(getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, TagType, StartLoc, SS, Name, NameLoc, attrs.getList()); } else if (TUK == Sema::TUK_Friend && TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { TagOrTempResult = Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, Name, NameLoc, attrs.getList(), MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); } else { if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Definition) { // FIXME: Diagnose this particular error. } bool IsDependent = false; // Don't pass down template parameter lists if this is just a tag // reference. For example, we don't need the template parameters here: // template class A *makeA(T t); MultiTemplateParamsArg TParams; if (TUK != Sema::TUK_Reference && TemplateParams) TParams = MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size()); // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, SourceLocation(), false, clang::TypeResult()); // If ActOnTag said the type was dependent, try again with the // less common call. if (IsDependent) { assert(TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend); TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK, SS, Name, StartLoc, NameLoc); } } // If there is a body, parse it and inform the actions module. if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || isCXX0XFinalKeyword()); if (getLangOpts().CPlusPlus) ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); else ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); } const char *PrevSpec = 0; unsigned DiagID; bool Result; if (!TypeResult.isInvalid()) { Result = DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, DiagID, TypeResult.get()); } else if (!TagOrTempResult.isInvalid()) { Result = DS.SetTypeSpecType(TagType, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, DiagID, TagOrTempResult.get(), Owned); } else { DS.SetTypeSpecError(); return; } if (Result) Diag(StartLoc, DiagID) << PrevSpec; // At this point, we've successfully parsed a class-specifier in 'definition' // form (e.g. "struct foo { int x; }". While we could just return here, we're // going to look at what comes after it to improve error recovery. If an // impossible token occurs next, we assume that the programmer forgot a ; at // the end of the declaration and recover that way. // // This switch enumerates the valid "follow" set for definition. if (TUK == Sema::TUK_Definition) { bool ExpectedSemi = true; switch (Tok.getKind()) { default: break; case tok::semi: // struct foo {...} ; case tok::star: // struct foo {...} * P; case tok::amp: // struct foo {...} & R = ... case tok::identifier: // struct foo {...} V ; case tok::r_paren: //(struct foo {...} ) {4} case tok::annot_cxxscope: // struct foo {...} a:: b; case tok::annot_typename: // struct foo {...} a ::b; case tok::annot_template_id: // struct foo {...} a ::b; case tok::l_paren: // struct foo {...} ( x); case tok::comma: // __builtin_offsetof(struct foo{...} , ExpectedSemi = false; break; // Type qualifiers case tok::kw_const: // struct foo {...} const x; case tok::kw_volatile: // struct foo {...} volatile x; case tok::kw_restrict: // struct foo {...} restrict x; case tok::kw_inline: // struct foo {...} inline foo() {}; // Storage-class specifiers case tok::kw_static: // struct foo {...} static x; case tok::kw_extern: // struct foo {...} extern x; case tok::kw_typedef: // struct foo {...} typedef x; case tok::kw_register: // struct foo {...} register x; case tok::kw_auto: // struct foo {...} auto x; case tok::kw_mutable: // struct foo {...} mutable x; case tok::kw_constexpr: // struct foo {...} constexpr x; // As shown above, type qualifiers and storage class specifiers absolutely // can occur after class specifiers according to the grammar. However, // almost no one actually writes code like this. If we see one of these, // it is much more likely that someone missed a semi colon and the // type/storage class specifier we're seeing is part of the *next* // intended declaration, as in: // // struct foo { ... } // typedef int X; // // We'd really like to emit a missing semicolon error instead of emitting // an error on the 'int' saying that you can't have two type specifiers in // the same declaration of X. Because of this, we look ahead past this // token to see if it's a type specifier. If so, we know the code is // otherwise invalid, so we can produce the expected semi error. if (!isKnownToBeTypeSpecifier(NextToken())) ExpectedSemi = false; break; case tok::r_brace: // struct bar { struct foo {...} } // Missing ';' at end of struct is accepted as an extension in C mode. if (!getLangOpts().CPlusPlus) ExpectedSemi = false; break; } // C++ [temp]p3 In a template-declaration which defines a class, no // declarator is permitted. if (TemplateInfo.Kind) ExpectedSemi = true; if (ExpectedSemi) { ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, TagType == DeclSpec::TST_class ? "class" : TagType == DeclSpec::TST_struct? "struct" : "union"); // Push this token back into the preprocessor and change our current token // to ';' so that the rest of the code recovers as though there were an // ';' after the definition. PP.EnterToken(Tok); Tok.setKind(tok::semi); } } } /// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived]. /// /// base-clause : [C++ class.derived] /// ':' base-specifier-list /// base-specifier-list: /// base-specifier '...'[opt] /// base-specifier-list ',' base-specifier '...'[opt] void Parser::ParseBaseClause(Decl *ClassDecl) { assert(Tok.is(tok::colon) && "Not a base clause"); ConsumeToken(); // Build up an array of parsed base specifiers. SmallVector BaseInfo; while (true) { // Parse a base-specifier. BaseResult Result = ParseBaseSpecifier(ClassDecl); if (Result.isInvalid()) { // Skip the rest of this base specifier, up until the comma or // opening brace. SkipUntil(tok::comma, tok::l_brace, true, true); } else { // Add this to our array of base specifiers. BaseInfo.push_back(Result.get()); } // If the next token is a comma, consume it and keep reading // base-specifiers. if (Tok.isNot(tok::comma)) break; // Consume the comma. ConsumeToken(); } // Attach the base specifiers Actions.ActOnBaseSpecifiers(ClassDecl, BaseInfo.data(), BaseInfo.size()); } /// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is /// one entry in the base class list of a class specifier, for example: /// class foo : public bar, virtual private baz { /// 'public bar' and 'virtual private baz' are each base-specifiers. /// /// base-specifier: [C++ class.derived] /// ::[opt] nested-name-specifier[opt] class-name /// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt] /// base-type-specifier /// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt] /// base-type-specifier Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { bool IsVirtual = false; SourceLocation StartLoc = Tok.getLocation(); // Parse the 'virtual' keyword. if (Tok.is(tok::kw_virtual)) { ConsumeToken(); IsVirtual = true; } // Parse an (optional) access specifier. AccessSpecifier Access = getAccessSpecifierIfPresent(); if (Access != AS_none) ConsumeToken(); // Parse the 'virtual' keyword (again!), in case it came after the // access specifier. if (Tok.is(tok::kw_virtual)) { SourceLocation VirtualLoc = ConsumeToken(); if (IsVirtual) { // Complain about duplicate 'virtual' Diag(VirtualLoc, diag::err_dup_virtual) << FixItHint::CreateRemoval(VirtualLoc); } IsVirtual = true; } // Parse the class-name. SourceLocation EndLocation; SourceLocation BaseLoc; TypeResult BaseType = ParseBaseTypeSpecifier(BaseLoc, EndLocation); if (BaseType.isInvalid()) return true; // Parse the optional ellipsis (for a pack expansion). The ellipsis is // actually part of the base-specifier-list grammar productions, but we // parse it here for convenience. SourceLocation EllipsisLoc; if (Tok.is(tok::ellipsis)) EllipsisLoc = ConsumeToken(); // Find the complete source range for the base-specifier. SourceRange Range(StartLoc, EndLocation); // Notify semantic analysis that we have parsed a complete // base-specifier. return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, BaseType.get(), BaseLoc, EllipsisLoc); } /// getAccessSpecifierIfPresent - Determine whether the next token is /// a C++ access-specifier. /// /// access-specifier: [C++ class.derived] /// 'private' /// 'protected' /// 'public' AccessSpecifier Parser::getAccessSpecifierIfPresent() const { switch (Tok.getKind()) { default: return AS_none; case tok::kw_private: return AS_private; case tok::kw_protected: return AS_protected; case tok::kw_public: return AS_public; } } /// \brief If the given declarator has any parts for which parsing has to be -/// delayed, e.g., default arguments or an exception-specification, create a -/// late-parsed method declaration record to handle the parsing at the end of -/// the class definition. +/// delayed, e.g., default arguments, create a late-parsed method declaration +/// record to handle the parsing at the end of the class definition. void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, Decl *ThisDecl) { // We just declared a member function. If this member function - // has any default arguments or an exception-specification, we'll need to - // parse them later. + // has any default arguments, we'll need to parse them later. LateParsedMethodDeclaration *LateMethod = 0; DeclaratorChunk::FunctionTypeInfo &FTI = DeclaratorInfo.getFunctionTypeInfo(); - - // If there was a delayed exception-specification, hold onto its tokens. - if (FTI.getExceptionSpecType() == EST_Delayed) { - // Push this method onto the stack of late-parsed method - // declarations. - LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); - getCurrentClass().LateParsedDeclarations.push_back(LateMethod); - LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); - // Stash the exception-specification tokens in the late-pased mthod. - LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens; - FTI.ExceptionSpecTokens = 0; - - // Reserve space for the parameters. - LateMethod->DefaultArgs.reserve(FTI.NumArgs); - } - for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) { if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) { if (!LateMethod) { // Push this method onto the stack of late-parsed method // declarations. LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); getCurrentClass().LateParsedDeclarations.push_back(LateMethod); LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); // Add all of the parameters prior to this one (they don't // have default arguments). LateMethod->DefaultArgs.reserve(FTI.NumArgs); for (unsigned I = 0; I < ParamIdx; ++I) LateMethod->DefaultArgs.push_back( LateParsedDefaultArgument(FTI.ArgInfo[I].Param)); } // Add this parameter to the list of parameters (it may or may // not have a default argument). LateMethod->DefaultArgs.push_back( LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param, FTI.ArgInfo[ParamIdx].DefaultArgTokens)); } } } /// isCXX0XVirtSpecifier - Determine whether the given token is a C++0x /// virt-specifier. /// /// virt-specifier: /// override /// final VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const { if (!getLangOpts().CPlusPlus) return VirtSpecifiers::VS_None; if (Tok.is(tok::identifier)) { IdentifierInfo *II = Tok.getIdentifierInfo(); // Initialize the contextual keywords. if (!Ident_final) { Ident_final = &PP.getIdentifierTable().get("final"); Ident_override = &PP.getIdentifierTable().get("override"); } if (II == Ident_override) return VirtSpecifiers::VS_Override; if (II == Ident_final) return VirtSpecifiers::VS_Final; } return VirtSpecifiers::VS_None; } /// ParseOptionalCXX0XVirtSpecifierSeq - Parse a virt-specifier-seq. /// /// virt-specifier-seq: /// virt-specifier /// virt-specifier-seq virt-specifier void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { while (true) { VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier(); if (Specifier == VirtSpecifiers::VS_None) return; // C++ [class.mem]p8: // A virt-specifier-seq shall contain at most one of each virt-specifier. const char *PrevSpec = 0; if (VS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec)) Diag(Tok.getLocation(), diag::err_duplicate_virt_specifier) << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_override_control_keyword : diag::ext_override_control_keyword) << VirtSpecifiers::getSpecifierName(Specifier); ConsumeToken(); } } /// isCXX0XFinalKeyword - Determine whether the next token is a C++0x /// contextual 'final' keyword. bool Parser::isCXX0XFinalKeyword() const { if (!getLangOpts().CPlusPlus) return false; if (!Tok.is(tok::identifier)) return false; // Initialize the contextual keywords. if (!Ident_final) { Ident_final = &PP.getIdentifierTable().get("final"); Ident_override = &PP.getIdentifierTable().get("override"); } return Tok.getIdentifierInfo() == Ident_final; } /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. /// /// member-declaration: /// decl-specifier-seq[opt] member-declarator-list[opt] ';' /// function-definition ';'[opt] /// ::[opt] nested-name-specifier template[opt] unqualified-id ';'[TODO] /// using-declaration [TODO] /// [C++0x] static_assert-declaration /// template-declaration /// [GNU] '__extension__' member-declaration /// /// member-declarator-list: /// member-declarator /// member-declarator-list ',' member-declarator /// /// member-declarator: /// declarator virt-specifier-seq[opt] pure-specifier[opt] /// declarator constant-initializer[opt] /// [C++11] declarator brace-or-equal-initializer[opt] /// identifier[opt] ':' constant-expression /// /// virt-specifier-seq: /// virt-specifier /// virt-specifier-seq virt-specifier /// /// virt-specifier: /// override /// final /// /// pure-specifier: /// '= 0' /// /// constant-initializer: /// '=' constant-expression /// void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *AccessAttrs, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { if (Tok.is(tok::at)) { if (getLangOpts().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs)) Diag(Tok, diag::err_at_defs_cxx); else Diag(Tok, diag::err_at_in_class); ConsumeToken(); SkipUntil(tok::r_brace); return; } // Access declarations. if (!TemplateInfo.Kind && (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && !TryAnnotateCXXScopeToken() && Tok.is(tok::annot_cxxscope)) { bool isAccessDecl = false; if (NextToken().is(tok::identifier)) isAccessDecl = GetLookAheadToken(2).is(tok::semi); else isAccessDecl = NextToken().is(tok::kw_operator); if (isAccessDecl) { // Collect the scope specifier token we annotated earlier. CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); // Try to parse an unqualified-id. SourceLocation TemplateKWLoc; UnqualifiedId Name; if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), TemplateKWLoc, Name)) { SkipUntil(tok::semi); return; } // TODO: recover from mistakenly-qualified operator declarations. if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "access declaration", tok::semi)) return; Actions.ActOnUsingDeclaration(getCurScope(), AS, false, SourceLocation(), SS, Name, /* AttrList */ 0, /* IsTypeName */ false, SourceLocation()); return; } } // static_assert-declaration if (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) { // FIXME: Check for templates SourceLocation DeclEnd; ParseStaticAssertDeclaration(DeclEnd); return; } if (Tok.is(tok::kw_template)) { assert(!TemplateInfo.TemplateParams && "Nested template improperly parsed?"); SourceLocation DeclEnd; ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, AS, AccessAttrs); return; } // Handle: member-declaration ::= '__extension__' member-declaration if (Tok.is(tok::kw___extension__)) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); return ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo, TemplateDiags); } // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it // is a bitfield. ColonProtectionRAIIObject X(*this); ParsedAttributesWithRange attrs(AttrFactory); // Optional C++0x attribute-specifier MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); if (Tok.is(tok::kw_using)) { ProhibitAttributes(attrs); // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); if (Tok.is(tok::kw_namespace)) { Diag(UsingLoc, diag::err_using_namespace_in_class); SkipUntil(tok::semi, true, true); } else { SourceLocation DeclEnd; // Otherwise, it must be a using-declaration or an alias-declaration. ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS); } return; } // Hold late-parsed attributes so we can attach a Decl to them later. LateParsedAttrList CommonLateParsedAttrs; // decl-specifier-seq: // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this, TemplateDiags); DS.takeAttributesFrom(attrs); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, &CommonLateParsedAttrs); MultiTemplateParamsArg TemplateParams(Actions, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); if (Tok.is(tok::semi)) { ConsumeToken(); Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams); DS.complete(TheDecl); return; } ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); VirtSpecifiers VS; // Hold late-parsed attributes so we can attach a Decl to them later. LateParsedAttrList LateParsedAttrs; SourceLocation EqualLoc; bool HasInitializer = false; ExprResult Init; if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. ColonProtectionRAIIObject X(*this); // Parse the first declarator. ParseDeclarator(DeclaratorInfo); - // Error parsin g the declarator? + // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) ConsumeToken(); return; } ParseOptionalCXX0XVirtSpecifierSeq(VS); // If attributes exist after the declarator, but before an '{', parse them. MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); // MSVC permits pure specifier on inline functions declared at class scope. // Hence check for =0 before checking for function definition. if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) && DeclaratorInfo.isFunctionDeclarator() && NextToken().is(tok::numeric_constant)) { EqualLoc = ConsumeToken(); Init = ParseInitializer(); if (Init.isInvalid()) SkipUntil(tok::comma, true, true); else HasInitializer = true; } FunctionDefinitionKind DefinitionKind = FDK_Declaration; // function-definition: // // In C++11, a non-function declarator followed by an open brace is a // braced-init-list for an in-class member initialization, not an // erroneous function definition. if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus0x) { DefinitionKind = FDK_Definition; } else if (DeclaratorInfo.isFunctionDeclarator()) { if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) { DefinitionKind = FDK_Definition; } else if (Tok.is(tok::equal)) { const Token &KW = NextToken(); if (KW.is(tok::kw_default)) DefinitionKind = FDK_Defaulted; else if (KW.is(tok::kw_delete)) DefinitionKind = FDK_Deleted; } } if (DefinitionKind) { if (!DeclaratorInfo.isFunctionDeclarator()) { Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params); ConsumeBrace(); SkipUntil(tok::r_brace, /*StopAtSemi*/false); // Consume the optional ';' if (Tok.is(tok::semi)) ConsumeToken(); return; } if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_function_declared_typedef); // This recovery skips the entire function body. It would be nice // to simply call ParseCXXInlineMethodDef() below, however Sema // assumes the declarator represents a function, not a typedef. ConsumeBrace(); SkipUntil(tok::r_brace, /*StopAtSemi*/false); // Consume the optional ';' if (Tok.is(tok::semi)) ConsumeToken(); return; } Decl *FunDecl = ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo, VS, DefinitionKind, Init); for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { CommonLateParsedAttrs[i]->addDecl(FunDecl); } for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { LateParsedAttrs[i]->addDecl(FunDecl); } LateParsedAttrs.clear(); // Consume the ';' - it's optional unless we have a delete or default if (Tok.is(tok::semi)) { ConsumeToken(); } return; } } // member-declarator-list: // member-declarator // member-declarator-list ',' member-declarator SmallVector DeclsInGroup; ExprResult BitfieldSize; bool ExpectSemi = true; while (1) { // member-declarator: // declarator pure-specifier[opt] // declarator brace-or-equal-initializer[opt] // identifier[opt] ':' constant-expression if (Tok.is(tok::colon)) { ConsumeToken(); BitfieldSize = ParseConstantExpression(); if (BitfieldSize.isInvalid()) SkipUntil(tok::comma, true, true); } // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) SkipUntil(tok::comma, true, true); DeclaratorInfo.setAsmLabel(AsmLabel.release()); DeclaratorInfo.SetRangeEnd(Loc); } // If attributes exist after the declarator, parse them. MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); // FIXME: When g++ adds support for this, we'll need to check whether it // goes before or after the GNU attributes and __asm__. ParseOptionalCXX0XVirtSpecifierSeq(VS); bool HasDeferredInitializer = false; if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { if (BitfieldSize.get()) { Diag(Tok, diag::err_bitfield_member_init); SkipUntil(tok::comma, true, true); } else { HasInitializer = true; HasDeferredInitializer = !DeclaratorInfo.isDeclarationOfFunction() && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef; } } // NOTE: If Sema is the Action module and declarator is an instance field, // this call will *not* return the created decl; It will return null. // See Sema::ActOnCXXMemberDeclarator for details. Decl *ThisDecl = 0; if (DS.isFriendSpecified()) { // TODO: handle initializers, bitfields, 'delete' ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, move(TemplateParams)); } else { ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, DeclaratorInfo, move(TemplateParams), BitfieldSize.release(), VS, HasDeferredInitializer); if (AccessAttrs) Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, false, true); } // Set the Decl for any late parsed attributes for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { CommonLateParsedAttrs[i]->addDecl(ThisDecl); } for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { LateParsedAttrs[i]->addDecl(ThisDecl); } LateParsedAttrs.clear(); // Handle the initializer. if (HasDeferredInitializer) { // The initializer was deferred; parse it and cache the tokens. Diag(Tok, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_nonstatic_member_init : diag::ext_nonstatic_member_init); if (DeclaratorInfo.isArrayOfUnknownBound()) { // C++0x [dcl.array]p3: An array bound may also be omitted when the // declarator is followed by an initializer. // // A brace-or-equal-initializer for a member-declarator is not an // initializer in the grammar, so this is ill-formed. Diag(Tok, diag::err_incomplete_array_member_init); SkipUntil(tok::comma, true, true); if (ThisDecl) // Avoid later warnings about a class member of incomplete type. ThisDecl->setInvalidDecl(); } else ParseCXXNonStaticMemberInitializer(ThisDecl); } else if (HasInitializer) { // Normal initializer. if (!Init.isUsable()) Init = ParseCXXMemberInitializer(ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); if (Init.isInvalid()) SkipUntil(tok::comma, true, true); else if (ThisDecl) Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(), DS.getTypeSpecType() == DeclSpec::TST_auto); } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) { // No initializer. Actions.ActOnUninitializedDecl(ThisDecl, DS.getTypeSpecType() == DeclSpec::TST_auto); } if (ThisDecl) { Actions.FinalizeDeclaration(ThisDecl); DeclsInGroup.push_back(ThisDecl); } - if (DeclaratorInfo.isFunctionDeclarator() && + if (ThisDecl && DeclaratorInfo.isFunctionDeclarator() && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) { HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl); } DeclaratorInfo.complete(ThisDecl); // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) break; // Consume the comma. SourceLocation CommaLoc = ConsumeToken(); if (Tok.isAtStartOfLine() && !MightBeDeclarator(Declarator::MemberContext)) { // This comma was followed by a line-break and something which can't be // the start of a declarator. The comma was probably a typo for a // semicolon. Diag(CommaLoc, diag::err_expected_semi_declaration) << FixItHint::CreateReplacement(CommaLoc, ";"); ExpectSemi = false; break; } // Parse the next declarator. DeclaratorInfo.clear(); VS.clear(); BitfieldSize = true; Init = true; HasInitializer = false; DeclaratorInfo.setCommaLoc(CommaLoc); // Attributes are only allowed on the second declarator. MaybeParseGNUAttributes(DeclaratorInfo); if (Tok.isNot(tok::colon)) ParseDeclarator(DeclaratorInfo); } if (ExpectSemi && ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { // Skip to end of block or statement. SkipUntil(tok::r_brace, true, true); // If we stopped at a ';', eat it. if (Tok.is(tok::semi)) ConsumeToken(); return; } Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup.data(), DeclsInGroup.size()); } /// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or /// pure-specifier. Also detect and reject any attempted defaulted/deleted /// function definition. The location of the '=', if any, will be placed in /// EqualLoc. /// /// pure-specifier: /// '= 0' /// /// brace-or-equal-initializer: /// '=' initializer-expression /// braced-init-list /// /// initializer-clause: /// assignment-expression /// braced-init-list /// /// defaulted/deleted function-definition: /// '=' 'default' /// '=' 'delete' /// /// Prior to C++0x, the assignment-expression in an initializer-clause must /// be a constant-expression. ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, SourceLocation &EqualLoc) { assert((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && "Data member initializer not starting with '=' or '{'"); EnterExpressionEvaluationContext Context(Actions, Sema::PotentiallyEvaluated, D); if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); if (Tok.is(tok::kw_delete)) { // In principle, an initializer of '= delete p;' is legal, but it will // never type-check. It's better to diagnose it as an ill-formed expression // than as an ill-formed deleted non-function member. // An initializer of '= delete p, foo' will never be parsed, because // a top-level comma always ends the initializer expression. const Token &Next = NextToken(); if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) || Next.is(tok::eof)) { if (IsFunction) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) << 1 /* delete */; else Diag(ConsumeToken(), diag::err_deleted_non_function); return ExprResult(); } } else if (Tok.is(tok::kw_default)) { if (IsFunction) Diag(Tok, diag::err_default_delete_in_multiple_declaration) << 0 /* default */; else Diag(ConsumeToken(), diag::err_default_special_members); return ExprResult(); } } return ParseInitializer(); } /// ParseCXXMemberSpecification - Parse the class definition. /// /// member-specification: /// member-declaration member-specification[opt] /// access-specifier ':' member-specification[opt] /// void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, unsigned TagType, Decl *TagDecl) { assert((TagType == DeclSpec::TST_struct || TagType == DeclSpec::TST_union || TagType == DeclSpec::TST_class) && "Invalid TagType!"); PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, "parsing struct/union/class body"); // Determine whether this is a non-nested class. Note that local // classes are *not* considered to be nested classes. bool NonNestedClass = true; if (!ClassStack.empty()) { for (const Scope *S = getCurScope(); S; S = S->getParent()) { if (S->isClassScope()) { // We're inside a class scope, so this is a nested class. NonNestedClass = false; break; } if ((S->getFlags() & Scope::FnScope)) { // If we're in a function or function template declared in the // body of a class, then this is a local class rather than a // nested class. const Scope *Parent = S->getParent(); if (Parent->isTemplateParamScope()) Parent = Parent->getParent(); if (Parent->isClassScope()) break; } } } // Enter a scope for the class. ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope); // Note that we are parsing a new (potentially-nested) class definition. ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass); if (TagDecl) Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); SourceLocation FinalLoc; // Parse the optional 'final' keyword. if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { assert(isCXX0XFinalKeyword() && "not a class definition"); FinalLoc = ConsumeToken(); Diag(FinalLoc, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_override_control_keyword : diag::ext_override_control_keyword) << "final"; } if (Tok.is(tok::colon)) { ParseBaseClause(TagDecl); if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected_lbrace_after_base_specifiers); if (TagDecl) Actions.ActOnTagDefinitionError(getCurScope(), TagDecl); return; } } assert(Tok.is(tok::l_brace)); BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); if (TagDecl) Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc, T.getOpenLocation()); // C++ 11p3: Members of a class defined with the keyword class are private // by default. Members of a class defined with the keywords struct or union // are public by default. AccessSpecifier CurAS; if (TagType == DeclSpec::TST_class) CurAS = AS_private; else CurAS = AS_public; ParsedAttributes AccessAttrs(AttrFactory); if (TagDecl) { // While we still have something to read, read the member-declarations. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // Each iteration of this loop reads one member-declaration. if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); continue; } // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } if (Tok.is(tok::annot_pragma_vis)) { HandlePragmaVisibility(); continue; } if (Tok.is(tok::annot_pragma_pack)) { HandlePragmaPack(); continue; } AccessSpecifier AS = getAccessSpecifierIfPresent(); if (AS != AS_none) { // Current token is a C++ access specifier. CurAS = AS; SourceLocation ASLoc = Tok.getLocation(); unsigned TokLength = Tok.getLength(); ConsumeToken(); AccessAttrs.clear(); MaybeParseGNUAttributes(AccessAttrs); SourceLocation EndLoc; if (Tok.is(tok::colon)) { EndLoc = Tok.getLocation(); ConsumeToken(); } else if (Tok.is(tok::semi)) { EndLoc = Tok.getLocation(); ConsumeToken(); Diag(EndLoc, diag::err_expected_colon) << FixItHint::CreateReplacement(EndLoc, ":"); } else { EndLoc = ASLoc.getLocWithOffset(TokLength); Diag(EndLoc, diag::err_expected_colon) << FixItHint::CreateInsertion(EndLoc, ":"); } if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc, AccessAttrs.getList())) { // found another attribute than only annotations AccessAttrs.clear(); } continue; } // FIXME: Make sure we don't have a template here. // Parse all the comma separated declarators. ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList()); } T.consumeClose(); } else { SkipUntil(tok::r_brace, false, false); } // If attributes exist after class contents, parse them. ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); if (TagDecl) Actions.ActOnFinishCXXMemberSpecification(getCurScope(), RecordLoc, TagDecl, T.getOpenLocation(), T.getCloseLocation(), attrs.getList()); // C++11 [class.mem]p2: // Within the class member-specification, the class is regarded as complete - // within function bodies, default arguments, exception-specifications, and + // within function bodies, default arguments, and // brace-or-equal-initializers for non-static data members (including such // things in nested classes). if (TagDecl && NonNestedClass) { // We are not inside a nested class. This class and its nested classes // are complete and we can parse the delayed portions of method // declarations and the lexed inline method definitions, along with any // delayed attributes. SourceLocation SavedPrevTokLocation = PrevTokLocation; ParseLexedAttributes(getCurrentClass()); ParseLexedMethodDeclarations(getCurrentClass()); + + // We've finished with all pending member declarations. + Actions.ActOnFinishCXXMemberDecls(); + ParseLexedMemberInitializers(getCurrentClass()); ParseLexedMethodDefs(getCurrentClass()); PrevTokLocation = SavedPrevTokLocation; } if (TagDecl) Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, T.getCloseLocation()); // Leave the class scope. ParsingDef.Pop(); ClassScope.Exit(); } /// ParseConstructorInitializer - Parse a C++ constructor initializer, /// which explicitly initializes the members or base classes of a /// class (C++ [class.base.init]). For example, the three initializers /// after the ':' in the Derived constructor below: /// /// @code /// class Base { }; /// class Derived : Base { /// int x; /// float f; /// public: /// Derived(float f) : Base(), x(17), f(f) { } /// }; /// @endcode /// /// [C++] ctor-initializer: /// ':' mem-initializer-list /// /// [C++] mem-initializer-list: /// mem-initializer ...[opt] /// mem-initializer ...[opt] , mem-initializer-list void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'"); // Poison the SEH identifiers so they are flagged as illegal in constructor initializers PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); SourceLocation ColonLoc = ConsumeToken(); SmallVector MemInitializers; bool AnyErrors = false; do { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteConstructorInitializer(ConstructorDecl, MemInitializers.data(), MemInitializers.size()); return cutOffParsing(); } else { MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); if (!MemInit.isInvalid()) MemInitializers.push_back(MemInit.get()); else AnyErrors = true; } if (Tok.is(tok::comma)) ConsumeToken(); else if (Tok.is(tok::l_brace)) break; // If the next token looks like a base or member initializer, assume that // we're just missing a comma. else if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); Diag(Loc, diag::err_ctor_init_missing_comma) << FixItHint::CreateInsertion(Loc, ", "); } else { // Skip over garbage, until we get to '{'. Don't eat the '{'. Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); SkipUntil(tok::l_brace, true, true); break; } } while (true); Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, MemInitializers.data(), MemInitializers.size(), AnyErrors); } /// ParseMemInitializer - Parse a C++ member initializer, which is /// part of a constructor initializer that explicitly initializes one /// member or base class (C++ [class.base.init]). See /// ParseConstructorInitializer for an example. /// /// [C++] mem-initializer: /// mem-initializer-id '(' expression-list[opt] ')' /// [C++0x] mem-initializer-id braced-init-list /// /// [C++] mem-initializer-id: /// '::'[opt] nested-name-specifier[opt] class-name /// identifier Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // parse '::'[opt] nested-name-specifier[opt] CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); ParsedType TemplateTypeTy; if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); TemplateTypeTy = getTypeAnnotation(Tok); } } // Uses of decltype will already have been converted to annot_decltype by // ParseOptionalCXXScopeSpecifier at this point. if (!TemplateTypeTy && Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_decltype)) { Diag(Tok, diag::err_expected_member_or_base_name); return true; } IdentifierInfo *II = 0; DeclSpec DS(AttrFactory); SourceLocation IdLoc = Tok.getLocation(); if (Tok.is(tok::annot_decltype)) { // Get the decltype expression, if there is one. ParseDecltypeSpecifier(DS); } else { if (Tok.is(tok::identifier)) // Get the identifier. This may be a member name or a class name, // but we'll let the semantic analysis determine which it is. II = Tok.getIdentifierInfo(); ConsumeToken(); } // Parse the '('. if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); ExprResult InitList = ParseBraceInitializer(); if (InitList.isInvalid()) return true; SourceLocation EllipsisLoc; if (Tok.is(tok::ellipsis)) EllipsisLoc = ConsumeToken(); return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, TemplateTypeTy, DS, IdLoc, InitList.take(), EllipsisLoc); } else if(Tok.is(tok::l_paren)) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); // Parse the optional expression-list. ExprVector ArgExprs(Actions); CommaLocsTy CommaLocs; if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { SkipUntil(tok::r_paren); return true; } T.consumeClose(); SourceLocation EllipsisLoc; if (Tok.is(tok::ellipsis)) EllipsisLoc = ConsumeToken(); return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, TemplateTypeTy, DS, IdLoc, T.getOpenLocation(), ArgExprs.take(), ArgExprs.size(), T.getCloseLocation(), EllipsisLoc); } Diag(Tok, getLangOpts().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace : diag::err_expected_lparen); return true; } /// \brief Parse a C++ exception-specification if present (C++0x [except.spec]). /// /// exception-specification: /// dynamic-exception-specification /// noexcept-specification /// /// noexcept-specification: /// 'noexcept' /// 'noexcept' '(' constant-expression ')' ExceptionSpecificationType -Parser::tryParseExceptionSpecification(bool Delayed, +Parser::tryParseExceptionSpecification( SourceRange &SpecificationRange, SmallVectorImpl &DynamicExceptions, SmallVectorImpl &DynamicExceptionRanges, - ExprResult &NoexceptExpr, - CachedTokens *&ExceptionSpecTokens) { + ExprResult &NoexceptExpr) { ExceptionSpecificationType Result = EST_None; - ExceptionSpecTokens = 0; - - // Handle delayed parsing of exception-specifications. - if (Delayed) { - if (Tok.isNot(tok::kw_throw) && Tok.isNot(tok::kw_noexcept)) - return EST_None; - // Consume and cache the starting token. - bool IsNoexcept = Tok.is(tok::kw_noexcept); - Token StartTok = Tok; - SpecificationRange = SourceRange(ConsumeToken()); - - // Check for a '('. - if (!Tok.is(tok::l_paren)) { - // If this is a bare 'noexcept', we're done. - if (IsNoexcept) { - Diag(Tok, diag::warn_cxx98_compat_noexcept_decl); - NoexceptExpr = 0; - return EST_BasicNoexcept; - } - - Diag(Tok, diag::err_expected_lparen_after) << "throw"; - return EST_DynamicNone; - } - - // Cache the tokens for the exception-specification. - ExceptionSpecTokens = new CachedTokens; - ExceptionSpecTokens->push_back(StartTok); // 'throw' or 'noexcept' - ExceptionSpecTokens->push_back(Tok); // '(' - SpecificationRange.setEnd(ConsumeParen()); // '(' - - if (!ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens, - /*StopAtSemi=*/true, - /*ConsumeFinalToken=*/true)) { - NoexceptExpr = 0; - delete ExceptionSpecTokens; - ExceptionSpecTokens = 0; - return IsNoexcept? EST_BasicNoexcept : EST_DynamicNone; - } - SpecificationRange.setEnd(Tok.getLocation()); - - // Add the 'stop' token. - Token End; - End.startToken(); - End.setKind(tok::cxx_exceptspec_end); - End.setLocation(Tok.getLocation()); - ExceptionSpecTokens->push_back(End); - return EST_Delayed; - } - // See if there's a dynamic specification. if (Tok.is(tok::kw_throw)) { Result = ParseDynamicExceptionSpecification(SpecificationRange, DynamicExceptions, DynamicExceptionRanges); assert(DynamicExceptions.size() == DynamicExceptionRanges.size() && "Produced different number of exception types and ranges."); } // If there's no noexcept specification, we're done. if (Tok.isNot(tok::kw_noexcept)) return Result; Diag(Tok, diag::warn_cxx98_compat_noexcept_decl); // If we already had a dynamic specification, parse the noexcept for, // recovery, but emit a diagnostic and don't store the results. SourceRange NoexceptRange; ExceptionSpecificationType NoexceptType = EST_None; SourceLocation KeywordLoc = ConsumeToken(); if (Tok.is(tok::l_paren)) { // There is an argument. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); NoexceptType = EST_ComputedNoexcept; NoexceptExpr = ParseConstantExpression(); // The argument must be contextually convertible to bool. We use // ActOnBooleanCondition for this purpose. if (!NoexceptExpr.isInvalid()) NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc, NoexceptExpr.get()); T.consumeClose(); NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation()); } else { // There is no argument. NoexceptType = EST_BasicNoexcept; NoexceptRange = SourceRange(KeywordLoc, KeywordLoc); } if (Result == EST_None) { SpecificationRange = NoexceptRange; Result = NoexceptType; // If there's a dynamic specification after a noexcept specification, // parse that and ignore the results. if (Tok.is(tok::kw_throw)) { Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification); ParseDynamicExceptionSpecification(NoexceptRange, DynamicExceptions, DynamicExceptionRanges); } } else { Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification); } return Result; } /// ParseDynamicExceptionSpecification - Parse a C++ /// dynamic-exception-specification (C++ [except.spec]). /// /// dynamic-exception-specification: /// 'throw' '(' type-id-list [opt] ')' /// [MS] 'throw' '(' '...' ')' /// /// type-id-list: /// type-id ... [opt] /// type-id-list ',' type-id ... [opt] /// ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( SourceRange &SpecificationRange, SmallVectorImpl &Exceptions, SmallVectorImpl &Ranges) { assert(Tok.is(tok::kw_throw) && "expected throw"); SpecificationRange.setBegin(ConsumeToken()); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen_after) << "throw"; SpecificationRange.setEnd(SpecificationRange.getBegin()); return EST_DynamicNone; } // Parse throw(...), a Microsoft extension that means "this function // can throw anything". if (Tok.is(tok::ellipsis)) { SourceLocation EllipsisLoc = ConsumeToken(); if (!getLangOpts().MicrosoftExt) Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec); T.consumeClose(); SpecificationRange.setEnd(T.getCloseLocation()); return EST_MSAny; } // Parse the sequence of type-ids. SourceRange Range; while (Tok.isNot(tok::r_paren)) { TypeResult Res(ParseTypeName(&Range)); if (Tok.is(tok::ellipsis)) { // C++0x [temp.variadic]p5: // - In a dynamic-exception-specification (15.4); the pattern is a // type-id. SourceLocation Ellipsis = ConsumeToken(); Range.setEnd(Ellipsis); if (!Res.isInvalid()) Res = Actions.ActOnPackExpansion(Res.get(), Ellipsis); } if (!Res.isInvalid()) { Exceptions.push_back(Res.get()); Ranges.push_back(Range); } if (Tok.is(tok::comma)) ConsumeToken(); else break; } T.consumeClose(); SpecificationRange.setEnd(T.getCloseLocation()); return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic; } /// ParseTrailingReturnType - Parse a trailing return type on a new-style /// function declaration. TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) { assert(Tok.is(tok::arrow) && "expected arrow"); ConsumeToken(); return ParseTypeName(&Range, Declarator::TrailingReturnContext); } /// \brief We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. Sema::ParsingClassState Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) { assert((NonNestedClass || !ClassStack.empty()) && "Nested class without outer class"); ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass)); return Actions.PushParsingClass(); } /// \brief Deallocate the given parsed class and all of its nested /// classes. void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) { for (unsigned I = 0, N = Class->LateParsedDeclarations.size(); I != N; ++I) delete Class->LateParsedDeclarations[I]; delete Class; } /// \brief Pop the top class of the stack of classes that are /// currently being parsed. /// /// This routine should be called when we have finished parsing the /// definition of a class, but have not yet popped the Scope /// associated with the class's definition. /// /// \returns true if the class we've popped is a top-level class, /// false otherwise. void Parser::PopParsingClass(Sema::ParsingClassState state) { assert(!ClassStack.empty() && "Mismatched push/pop for class parsing"); Actions.PopParsingClass(state); ParsingClass *Victim = ClassStack.top(); ClassStack.pop(); if (Victim->TopLevelClass) { // Deallocate all of the nested classes of this class, // recursively: we don't need to keep any of this information. DeallocateParsedClasses(Victim); return; } assert(!ClassStack.empty() && "Missing top-level class?"); if (Victim->LateParsedDeclarations.empty()) { // The victim is a nested class, but we will not need to perform // any processing after the definition of this class since it has // no members whose handling was delayed. Therefore, we can just // remove this nested class. DeallocateParsedClasses(Victim); return; } // This nested class has some members that will need to be processed // after the top-level class is completely defined. Therefore, add // it to the list of nested classes within its parent. assert(getCurScope()->isClassScope() && "Nested class outside of class scope?"); ClassStack.top()->LateParsedDeclarations.push_back(new LateParsedClass(this, Victim)); Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope(); } /// \brief Try to parse an 'identifier' which appears within an attribute-token. /// /// \return the parsed identifier on success, and 0 if the next token is not an /// attribute-token. /// /// C++11 [dcl.attr.grammar]p3: /// If a keyword or an alternative token that satisfies the syntactic /// requirements of an identifier is contained in an attribute-token, /// it is considered an identifier. IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { switch (Tok.getKind()) { default: // Identifiers and keywords have identifier info attached. if (IdentifierInfo *II = Tok.getIdentifierInfo()) { Loc = ConsumeToken(); return II; } return 0; case tok::ampamp: // 'and' case tok::pipe: // 'bitor' case tok::pipepipe: // 'or' case tok::caret: // 'xor' case tok::tilde: // 'compl' case tok::amp: // 'bitand' case tok::ampequal: // 'and_eq' case tok::pipeequal: // 'or_eq' case tok::caretequal: // 'xor_eq' case tok::exclaim: // 'not' case tok::exclaimequal: // 'not_eq' // Alternative tokens do not have identifier info, but their spelling // starts with an alphabetical character. llvm::SmallString<8> SpellingBuf; StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf); if (std::isalpha(Spelling[0])) { Loc = ConsumeToken(); return &PP.getIdentifierTable().get(Spelling.data()); } return 0; } } /// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. Currently /// only parses standard attributes. /// /// [C++11] attribute-specifier: /// '[' '[' attribute-list ']' ']' /// alignment-specifier /// /// [C++11] attribute-list: /// attribute[opt] /// attribute-list ',' attribute[opt] /// attribute '...' /// attribute-list ',' attribute '...' /// /// [C++11] attribute: /// attribute-token attribute-argument-clause[opt] /// /// [C++11] attribute-token: /// identifier /// attribute-scoped-token /// /// [C++11] attribute-scoped-token: /// attribute-namespace '::' identifier /// /// [C++11] attribute-namespace: /// identifier /// /// [C++11] attribute-argument-clause: /// '(' balanced-token-seq ')' /// /// [C++11] balanced-token-seq: /// balanced-token /// balanced-token-seq balanced-token /// /// [C++11] balanced-token: /// '(' balanced-token-seq ')' /// '[' balanced-token-seq ']' /// '{' balanced-token-seq '}' /// any token but '(', ')', '[', ']', '{', or '}' void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, SourceLocation *endLoc) { if (Tok.is(tok::kw_alignas)) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); ParseAlignmentSpecifier(attrs, endLoc); return; } assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) && "Not a C++11 attribute list"); Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute); ConsumeBracket(); ConsumeBracket(); while (Tok.isNot(tok::r_square)) { // attribute not present if (Tok.is(tok::comma)) { ConsumeToken(); continue; } SourceLocation ScopeLoc, AttrLoc; IdentifierInfo *ScopeName = 0, *AttrName = 0; AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); if (!AttrName) // Break out to the "expected ']'" diagnostic. break; // scoped attribute if (Tok.is(tok::coloncolon)) { ConsumeToken(); ScopeName = AttrName; ScopeLoc = AttrLoc; AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); if (!AttrName) { Diag(Tok.getLocation(), diag::err_expected_ident); SkipUntil(tok::r_square, tok::comma, true, true); continue; } } bool AttrParsed = false; // No scoped names are supported; ideally we could put all non-standard // attributes into namespaces. if (!ScopeName) { switch (AttributeList::getKind(AttrName)) { // No arguments case AttributeList::AT_carries_dependency: case AttributeList::AT_noreturn: { if (Tok.is(tok::l_paren)) { Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) << AttrName->getName(); break; } attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, 0, SourceLocation(), 0, 0, false, true); AttrParsed = true; break; } // Silence warnings default: break; } } // Skip the entire parameter clause, if any if (!AttrParsed && Tok.is(tok::l_paren)) { ConsumeParen(); // SkipUntil maintains the balancedness of tokens. SkipUntil(tok::r_paren, false); } if (Tok.is(tok::ellipsis)) { if (AttrParsed) Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) << AttrName->getName(); ConsumeToken(); } } if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) SkipUntil(tok::r_square, false); if (endLoc) *endLoc = Tok.getLocation(); if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) SkipUntil(tok::r_square, false); } /// ParseCXX11Attributes - Parse a C++0x attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc) { SourceLocation StartLoc = Tok.getLocation(), Loc; if (!endLoc) endLoc = &Loc; do { ParseCXX11AttributeSpecifier(attrs, endLoc); } while (isCXX11AttributeSpecifier()); attrs.Range = SourceRange(StartLoc, *endLoc); } /// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] /// /// [MS] ms-attribute: /// '[' token-seq ']' /// /// [MS] ms-attribute-seq: /// ms-attribute[opt] /// ms-attribute ms-attribute-seq void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, SourceLocation *endLoc) { assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list"); while (Tok.is(tok::l_square)) { // FIXME: If this is actually a C++11 attribute, parse it as one. ConsumeBracket(); SkipUntil(tok::r_square, true, true); if (endLoc) *endLoc = Tok.getLocation(); ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); } } void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, AccessSpecifier& CurAS) { IfExistsCondition Result; if (ParseMicrosoftIfExistsCondition(Result)) return; BalancedDelimiterTracker Braces(*this, tok::l_brace); if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected_lbrace); return; } switch (Result.Behavior) { case IEB_Parse: // Parse the declarations below. break; case IEB_Dependent: Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists) << Result.IsIfExists; // Fall through to skip. case IEB_Skip: Braces.skipToEnd(); return; } while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // __if_exists, __if_not_exists can nest. if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); continue; } // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) << DeclSpec::getSpecifierName((DeclSpec::TST)TagType) << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } AccessSpecifier AS = getAccessSpecifierIfPresent(); if (AS != AS_none) { // Current token is a C++ access specifier. CurAS = AS; SourceLocation ASLoc = Tok.getLocation(); ConsumeToken(); if (Tok.is(tok::colon)) Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation()); else Diag(Tok, diag::err_expected_colon); ConsumeToken(); continue; } // Parse all the comma separated declarators. ParseCXXClassMemberDeclaration(CurAS, 0); } Braces.consumeClose(); } Index: vendor/clang/dist/lib/Parse/ParseExpr.cpp =================================================================== --- vendor/clang/dist/lib/Parse/ParseExpr.cpp (revision 235808) +++ vendor/clang/dist/lib/Parse/ParseExpr.cpp (revision 235809) @@ -1,2431 +1,2431 @@ //===--- ParseExpr.cpp - Expression Parsing -------------------------------===// // // 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 Expression parsing implementation. Expressions in // C99 basically consist of a bunch of binary operators with unary operators and // other random stuff at the leaves. // // In the C99 grammar, these unary operators bind tightest and are represented // as the 'cast-expression' production. Everything else is either a binary // operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are // handled by ParseCastExpression, the higher level pieces are handled by // ParseBinaryExpression. // //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Basic/PrettyStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallString.h" using namespace clang; /// getBinOpPrecedence - Return the precedence of the specified binary operator /// token. static prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator, bool CPlusPlus0x) { switch (Kind) { case tok::greater: // C++ [temp.names]p3: // [...] When parsing a template-argument-list, the first // non-nested > is taken as the ending delimiter rather than a // greater-than operator. [...] if (GreaterThanIsOperator) return prec::Relational; return prec::Unknown; case tok::greatergreater: // C++0x [temp.names]p3: // // [...] Similarly, the first non-nested >> is treated as two // consecutive but distinct > tokens, the first of which is // taken as the end of the template-argument-list and completes // the template-id. [...] if (GreaterThanIsOperator || !CPlusPlus0x) return prec::Shift; return prec::Unknown; default: return prec::Unknown; case tok::comma: return prec::Comma; case tok::equal: case tok::starequal: case tok::slashequal: case tok::percentequal: case tok::plusequal: case tok::minusequal: case tok::lesslessequal: case tok::greatergreaterequal: case tok::ampequal: case tok::caretequal: case tok::pipeequal: return prec::Assignment; case tok::question: return prec::Conditional; case tok::pipepipe: return prec::LogicalOr; case tok::ampamp: return prec::LogicalAnd; case tok::pipe: return prec::InclusiveOr; case tok::caret: return prec::ExclusiveOr; case tok::amp: return prec::And; case tok::exclaimequal: case tok::equalequal: return prec::Equality; case tok::lessequal: case tok::less: case tok::greaterequal: return prec::Relational; case tok::lessless: return prec::Shift; case tok::plus: case tok::minus: return prec::Additive; case tok::percent: case tok::slash: case tok::star: return prec::Multiplicative; case tok::periodstar: case tok::arrowstar: return prec::PointerToMember; } } /// ParseExpression - Simple precedence-based parser for binary/ternary /// operators. /// /// Note: we diverge from the C99 grammar when parsing the assignment-expression /// production. C99 specifies that the LHS of an assignment operator should be /// parsed as a unary-expression, but consistency dictates that it be a /// conditional-expession. In practice, the important thing here is that the /// LHS of an assignment has to be an l-value, which productions between /// unary-expression and conditional-expression don't produce. Because we want /// consistency, we parse the LHS as a conditional-expression, then check for /// l-value-ness in semantic analysis stages. /// /// pm-expression: [C++ 5.5] /// cast-expression /// pm-expression '.*' cast-expression /// pm-expression '->*' cast-expression /// /// multiplicative-expression: [C99 6.5.5] /// Note: in C++, apply pm-expression instead of cast-expression /// cast-expression /// multiplicative-expression '*' cast-expression /// multiplicative-expression '/' cast-expression /// multiplicative-expression '%' cast-expression /// /// additive-expression: [C99 6.5.6] /// multiplicative-expression /// additive-expression '+' multiplicative-expression /// additive-expression '-' multiplicative-expression /// /// shift-expression: [C99 6.5.7] /// additive-expression /// shift-expression '<<' additive-expression /// shift-expression '>>' additive-expression /// /// relational-expression: [C99 6.5.8] /// shift-expression /// relational-expression '<' shift-expression /// relational-expression '>' shift-expression /// relational-expression '<=' shift-expression /// relational-expression '>=' shift-expression /// /// equality-expression: [C99 6.5.9] /// relational-expression /// equality-expression '==' relational-expression /// equality-expression '!=' relational-expression /// /// AND-expression: [C99 6.5.10] /// equality-expression /// AND-expression '&' equality-expression /// /// exclusive-OR-expression: [C99 6.5.11] /// AND-expression /// exclusive-OR-expression '^' AND-expression /// /// inclusive-OR-expression: [C99 6.5.12] /// exclusive-OR-expression /// inclusive-OR-expression '|' exclusive-OR-expression /// /// logical-AND-expression: [C99 6.5.13] /// inclusive-OR-expression /// logical-AND-expression '&&' inclusive-OR-expression /// /// logical-OR-expression: [C99 6.5.14] /// logical-AND-expression /// logical-OR-expression '||' logical-AND-expression /// /// conditional-expression: [C99 6.5.15] /// logical-OR-expression /// logical-OR-expression '?' expression ':' conditional-expression /// [GNU] logical-OR-expression '?' ':' conditional-expression /// [C++] the third operand is an assignment-expression /// /// assignment-expression: [C99 6.5.16] /// conditional-expression /// unary-expression assignment-operator assignment-expression /// [C++] throw-expression [C++ 15] /// /// assignment-operator: one of /// = *= /= %= += -= <<= >>= &= ^= |= /// /// expression: [C99 6.5.17] /// assignment-expression ...[opt] /// expression ',' assignment-expression ...[opt] ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { ExprResult LHS(ParseAssignmentExpression(isTypeCast)); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } /// This routine is called when the '@' is seen and consumed. /// Current token is an Identifier and is not a 'try'. This /// routine is necessary to disambiguate @try-statement from, /// for example, @encode-expression. /// ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { ExprResult LHS(ParseObjCAtExpression(AtLoc)); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } /// This routine is called when a leading '__extension__' is seen and /// consumed. This is necessary because the token gets consumed in the /// process of disambiguating between an expression and a declaration. ExprResult Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { ExprResult LHS(true); { // Silence extension warnings in the sub-expression ExtensionRAIIObject O(Diags); LHS = ParseCastExpression(false); } if (!LHS.isInvalid()) LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__, LHS.take()); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); } /// ParseAssignmentExpression - Parse an expr that doesn't include commas. ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); cutOffParsing(); return ExprError(); } if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, isTypeCast); return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); } /// ParseAssignmentExprWithObjCMessageExprStart - Parse an assignment expression /// where part of an objc message send has already been parsed. In this case /// LBracLoc indicates the location of the '[' of the message send, and either /// ReceiverName or ReceiverExpr is non-null indicating the receiver of the /// message. /// /// Since this handles full assignment-expression's, it handles postfix /// expressions and other binary operators for these expressions as well. ExprResult Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, SourceLocation SuperLoc, ParsedType ReceiverType, Expr *ReceiverExpr) { ExprResult R = ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, ReceiverType, ReceiverExpr); R = ParsePostfixExpressionSuffix(R); return ParseRHSOfBinaryExpression(R, prec::Assignment); } ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { // C++03 [basic.def.odr]p2: // An expression is potentially evaluated unless it appears where an // integral constant expression is required (see 5.19) [...]. // C++98 and C++11 have no such rule, but this is only a defect in C++98. EnterExpressionEvaluationContext Unevaluated(Actions, Sema::ConstantEvaluated); ExprResult LHS(ParseCastExpression(false, false, isTypeCast)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); return Actions.ActOnConstantExpression(Res); } /// ParseRHSOfBinaryExpression - Parse a binary expression that starts with /// LHS and has a precedence of at least MinPrec. ExprResult Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLangOpts().CPlusPlus0x); SourceLocation ColonLoc; while (1) { // If this token has a lower precedence than we are allowed to parse (e.g. // because we are called recursively, or because the token is not a binop), // then we are done! if (NextTokPrec < MinPrec) return move(LHS); // Consume the operator, saving the operator token for error reporting. Token OpToken = Tok; ConsumeToken(); // Special case handling for the ternary operator. ExprResult TernaryMiddle(true); if (NextTokPrec == prec::Conditional) { if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. ColonProtectionRAIIObject X(*this); // Handle this production specially: // logical-OR-expression '?' expression ':' conditional-expression // In particular, the RHS of the '?' is 'expression', not // 'logical-OR-expression' as we might expect. TernaryMiddle = ParseExpression(); if (TernaryMiddle.isInvalid()) { LHS = ExprError(); TernaryMiddle = 0; } } else { // Special case handling of "X ? Y : Z" where Y is empty: // logical-OR-expression '?' ':' conditional-expression [GNU] TernaryMiddle = 0; Diag(Tok, diag::ext_gnu_conditional_expr); } if (Tok.is(tok::colon)) { // Eat the colon. ColonLoc = ConsumeToken(); } else { // Otherwise, we're missing a ':'. Assume that this was a typo that // the user forgot. If we're not in a macro expansion, we can suggest // a fixit hint. If there were two spaces before the current token, // suggest inserting the colon in between them, otherwise insert ": ". SourceLocation FILoc = Tok.getLocation(); const char *FIText = ": "; const SourceManager &SM = PP.getSourceManager(); if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc, &FILoc)) { assert(FILoc.isFileID()); bool IsInvalid = false; const char *SourcePtr = SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid); if (!IsInvalid && *SourcePtr == ' ') { SourcePtr = SM.getCharacterData(FILoc.getLocWithOffset(-2), &IsInvalid); if (!IsInvalid && *SourcePtr == ' ') { FILoc = FILoc.getLocWithOffset(-1); FIText = ":"; } } } Diag(Tok, diag::err_expected_colon) << FixItHint::CreateInsertion(FILoc, FIText); Diag(OpToken, diag::note_matching) << "?"; ColonLoc = Tok.getLocation(); } } // Code completion for the right-hand side of an assignment expression // goes through a special hook that takes the left-hand side into account. if (Tok.is(tok::code_completion) && NextTokPrec == prec::Assignment) { Actions.CodeCompleteAssignmentRHS(getCurScope(), LHS.get()); cutOffParsing(); return ExprError(); } // Parse another leaf here for the RHS of the operator. // ParseCastExpression works here because all RHS expressions in C have it // as a prefix, at least. However, in C++, an assignment-expression could // be a throw-expression, which is not a valid cast-expression. // Therefore we need some special-casing here. // Also note that the third operand of the conditional operator is // an assignment-expression in C++, and in C++11, we can have a // braced-init-list on the RHS of an assignment. For better diagnostics, // parse as if we were allowed braced-init-lists everywhere, and check that // they only appear on the RHS of assignments later. ExprResult RHS; bool RHSIsInitList = false; if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { RHS = ParseBraceInitializer(); RHSIsInitList = true; } else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional) RHS = ParseAssignmentExpression(); else RHS = ParseCastExpression(false); if (RHS.isInvalid()) LHS = ExprError(); // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. prec::Level ThisPrec = NextTokPrec; NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLangOpts().CPlusPlus0x); // Assignment and conditional expressions are right-associative. bool isRightAssoc = ThisPrec == prec::Conditional || ThisPrec == prec::Assignment; // Get the precedence of the operator to the right of the RHS. If it binds // more tightly with RHS than we do, evaluate it completely first. if (ThisPrec < NextTokPrec || (ThisPrec == NextTokPrec && isRightAssoc)) { if (!RHS.isInvalid() && RHSIsInitList) { Diag(Tok, diag::err_init_list_bin_op) << /*LHS*/0 << PP.getSpelling(Tok) << Actions.getExprRange(RHS.get()); RHS = ExprError(); } // If this is left-associative, only parse things on the RHS that bind // more tightly than the current operator. If it is left-associative, it // is okay, to bind exactly as tightly. For example, compile A=B=C=D as // A=(B=(C=D)), where each paren is a level of recursion here. // The function takes ownership of the RHS. RHS = ParseRHSOfBinaryExpression(RHS, static_cast(ThisPrec + !isRightAssoc)); RHSIsInitList = false; if (RHS.isInvalid()) LHS = ExprError(); NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLangOpts().CPlusPlus0x); } assert(NextTokPrec <= ThisPrec && "Recursion didn't work!"); if (!RHS.isInvalid() && RHSIsInitList) { if (ThisPrec == prec::Assignment) { Diag(OpToken, diag::warn_cxx98_compat_generalized_initializer_lists) << Actions.getExprRange(RHS.get()); } else { Diag(OpToken, diag::err_init_list_bin_op) << /*RHS*/1 << PP.getSpelling(OpToken) << Actions.getExprRange(RHS.get()); LHS = ExprError(); } } if (!LHS.isInvalid()) { // Combine the LHS and RHS into the LHS (e.g. build AST). if (TernaryMiddle.isInvalid()) { // If we're using '>>' as an operator within a template // argument list (in C++98), suggest the addition of // parentheses so that the code remains well-formed in C++0x. if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater)) SuggestParentheses(OpToken.getLocation(), diag::warn_cxx0x_right_shift_in_template_arg, SourceRange(Actions.getExprRange(LHS.get()).getBegin(), Actions.getExprRange(RHS.get()).getEnd())); LHS = Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(), OpToken.getKind(), LHS.take(), RHS.take()); } else LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, LHS.take(), TernaryMiddle.take(), RHS.take()); } } } /// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is /// true, parse a unary-expression. isAddressOfOperand exists because an /// id-expression that is the operand of address-of gets special treatment /// due to member pointers. /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, TypeCastState isTypeCast) { bool NotCastExpr; ExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, isTypeCast); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return move(Res); } namespace { class CastExpressionIdValidator : public CorrectionCandidateCallback { public: CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes) : AllowNonTypes(AllowNonTypes) { WantTypeSpecifiers = AllowTypes; } virtual bool ValidateCandidate(const TypoCorrection &candidate) { NamedDecl *ND = candidate.getCorrectionDecl(); if (!ND) return candidate.isKeyword(); if (isa(ND)) return WantTypeSpecifiers; return AllowNonTypes; } private: bool AllowNonTypes; }; } /// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is /// true, parse a unary-expression. isAddressOfOperand exists because an /// id-expression that is the operand of address-of gets special treatment /// due to member pointers. NotCastExpr is set to true if the token is not the /// start of a cast-expression, and no diagnostic is emitted in this case. /// /// cast-expression: [C99 6.5.4] /// unary-expression /// '(' type-name ')' cast-expression /// /// unary-expression: [C99 6.5.3] /// postfix-expression /// '++' unary-expression /// '--' unary-expression /// unary-operator cast-expression /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [C++11] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++11] 'alignof' '(' type-id ')' /// [GNU] '&&' identifier /// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7] /// [C++] new-expression /// [C++] delete-expression /// /// unary-operator: one of /// '&' '*' '+' '-' '~' '!' /// [GNU] '__extension__' '__real' '__imag' /// /// primary-expression: [C99 6.5.1] /// [C99] identifier /// [C++] id-expression /// constant /// string-literal /// [C++] boolean-literal [C++ 2.13.5] /// [C++11] 'nullptr' [C++11 2.14.7] /// [C++11] user-defined-literal /// '(' expression ')' /// [C11] generic-selection /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [GNU] '__PRETTY_FUNCTION__' /// [GNU] '(' compound-statement ')' /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [GNU] '__null' /// [OBJC] '[' objc-message-expr ']' /// [OBJC] '@selector' '(' objc-selector-arg ')' /// [OBJC] '@protocol' '(' identifier ')' /// [OBJC] '@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3] /// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++11] typename-specifier braced-init-list [C++11 5.2.3] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'typeid' '(' expression ')' [C++ 5.2p1] /// [C++] 'typeid' '(' type-id ')' [C++ 5.2p1] /// [C++] 'this' [C++ 9.3.2] /// [G++] unary-type-trait '(' type-id ')' /// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO] /// [EMBT] array-type-trait '(' type-id ',' integer ')' /// [clang] '^' block-literal /// /// constant: [C99 6.4.4] /// integer-constant /// floating-constant /// enumeration-constant -> identifier /// character-constant /// /// id-expression: [C++ 5.1] /// unqualified-id /// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id /// conversion-function-id /// '~' class-name /// template-id /// /// new-expression: [C++ 5.3.4] /// '::'[opt] 'new' new-placement[opt] new-type-id /// new-initializer[opt] /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// delete-expression: [C++ 5.3.5] /// '::'[opt] 'delete' cast-expression /// '::'[opt] 'delete' '[' ']' cast-expression /// /// [GNU/Embarcadero] unary-type-trait: /// '__is_arithmetic' /// '__is_floating_point' /// '__is_integral' /// '__is_lvalue_expr' /// '__is_rvalue_expr' /// '__is_complete_type' /// '__is_void' /// '__is_array' /// '__is_function' /// '__is_reference' /// '__is_lvalue_reference' /// '__is_rvalue_reference' /// '__is_fundamental' /// '__is_object' /// '__is_scalar' /// '__is_compound' /// '__is_pointer' /// '__is_member_object_pointer' /// '__is_member_function_pointer' /// '__is_member_pointer' /// '__is_const' /// '__is_volatile' /// '__is_trivial' /// '__is_standard_layout' /// '__is_signed' /// '__is_unsigned' /// /// [GNU] unary-type-trait: /// '__has_nothrow_assign' /// '__has_nothrow_copy' /// '__has_nothrow_constructor' /// '__has_trivial_assign' [TODO] /// '__has_trivial_copy' [TODO] /// '__has_trivial_constructor' /// '__has_trivial_destructor' /// '__has_virtual_destructor' /// '__is_abstract' [TODO] /// '__is_class' /// '__is_empty' [TODO] /// '__is_enum' /// '__is_final' /// '__is_pod' /// '__is_polymorphic' /// '__is_trivial' /// '__is_union' /// /// [Clang] unary-type-trait: /// '__trivially_copyable' /// /// binary-type-trait: /// [GNU] '__is_base_of' /// [MS] '__is_convertible_to' /// '__is_convertible' /// '__is_same' /// /// [Embarcadero] array-type-trait: /// '__array_rank' /// '__array_extent' /// /// [Embarcadero] expression-trait: /// '__is_lvalue_expr' /// '__is_rvalue_expr' /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, TypeCastState isTypeCast) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); NotCastExpr = false; // This handles all of cast-expression, unary-expression, postfix-expression, // and primary-expression. We handle them together like this for efficiency // and to simplify handling of an expression starting with a '(' token: which // may be one of a parenthesized expression, cast-expression, compound literal // expression, or statement expression. // // If the parsed tokens consist of a primary-expression, the cases below // break out of the switch; at the end we call ParsePostfixExpressionSuffix // to handle the postfix expression suffixes. Cases that cannot be followed // by postfix exprs should return without invoking // ParsePostfixExpressionSuffix. switch (SavedKind) { case tok::l_paren: { // If this expression is limited to being a unary-expression, the parent can // not start a cast expression. ParenParseOption ParenExprType = (isUnaryExpression && !getLangOpts().CPlusPlus)? CompoundLiteral : CastExpr; ParsedType CastTy; SourceLocation RParenLoc; { // The inside of the parens don't need to be a colon protected scope, and // isn't immediately a message send. ColonProtectionRAIIObject X(*this, false); Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, isTypeCast == IsTypeCast, CastTy, RParenLoc); } switch (ParenExprType) { case SimpleExpr: break; // Nothing else to do. case CompoundStmt: break; // Nothing else to do. case CompoundLiteral: // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of // postfix-expression exist, parse them now. break; case CastExpr: // We have parsed the cast-expression and no postfix-expr pieces are // following. return move(Res); } break; } // primary-expression case tok::numeric_constant: // constant: integer-constant // constant: floating-constant Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope()); ConsumeToken(); break; case tok::kw_true: case tok::kw_false: return ParseCXXBoolLiteral(); case tok::kw___objc_yes: case tok::kw___objc_no: return ParseObjCBoolLiteral(); case tok::kw_nullptr: Diag(Tok, diag::warn_cxx98_compat_nullptr); return Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); case tok::annot_primary_expr: assert(Res.get() == 0 && "Stray primary-expression annotation?"); Res = getExprAnnotation(Tok); ConsumeToken(); break; case tok::kw_decltype: case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. if (getLangOpts().CPlusPlus) { // Avoid the unnecessary parse-time lookup in the common case // where the syntax forbids a type. const Token &Next = NextToken(); if (Next.is(tok::coloncolon) || (!ColonIsSacred && Next.is(tok::colon)) || Next.is(tok::less) || Next.is(tok::l_paren) || Next.is(tok::l_brace)) { // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::identifier)) return ParseCastExpression(isUnaryExpression, isAddressOfOperand); } } // Consume the identifier so that we can see if it is followed by a '(' or // '.'. IdentifierInfo &II = *Tok.getIdentifierInfo(); SourceLocation ILoc = ConsumeToken(); // Support 'Class.property' and 'super.property' notation. if (getLangOpts().ObjC1 && Tok.is(tok::period) && (Actions.getTypeName(II, ILoc, getCurScope()) || // Allow the base to be 'super' if in an objc-method. (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) { ConsumeToken(); // Allow either an identifier or the keyword 'class' (in C++). if (Tok.isNot(tok::identifier) && !(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) { Diag(Tok, diag::err_expected_property_name); return ExprError(); } IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); SourceLocation PropertyLoc = ConsumeToken(); Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, ILoc, PropertyLoc); break; } // In an Objective-C method, if we have "super" followed by an identifier, // the token sequence is ill-formed. However, if there's a ':' or ']' after // that identifier, this is probably a message send with a missing open // bracket. Treat it as such. if (getLangOpts().ObjC1 && &II == Ident_super && !InMessageExpression && getCurScope()->isInObjcMethodScope() && ((Tok.is(tok::identifier) && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || Tok.is(tok::code_completion))) { Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(), 0); break; } // If we have an Objective-C class name followed by an identifier // and either ':' or ']', this is an Objective-C class message // send that's missing the opening '['. Recovery // appropriately. Also take this path if we're performing code // completion after an Objective-C class name. if (getLangOpts().ObjC1 && ((Tok.is(tok::identifier) && !InMessageExpression) || Tok.is(tok::code_completion))) { const Token& Next = NextToken(); if (Tok.is(tok::code_completion) || Next.is(tok::colon) || Next.is(tok::r_square)) if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope())) if (Typ.get()->isObjCObjectOrInterfaceType()) { // Fake up a Declarator to use with ActOnTypeName. DeclSpec DS(AttrFactory); DS.SetRangeStart(ILoc); DS.SetRangeEnd(ILoc); const char *PrevSpec = 0; unsigned DiagID; DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ); Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); if (Ty.isInvalid()) break; Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), Ty.get(), 0); break; } } // Make sure to pass down the right value for isAddressOfOperand. if (isAddressOfOperand && isPostfixExpressionSuffixStart()) isAddressOfOperand = false; // Function designators are allowed to be undeclared (C99 6.5.1p2), so we // need to know whether or not this identifier is a function designator or // not. UnqualifiedId Name; CXXScopeSpec ScopeSpec; SourceLocation TemplateKWLoc; CastExpressionIdValidator Validator(isTypeCast != NotTypeCast, isTypeCast != IsTypeCast); Name.setIdentifier(&II, ILoc); Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren), isAddressOfOperand, &Validator); break; } case tok::char_constant: // constant: character-constant case tok::wide_char_constant: case tok::utf16_char_constant: case tok::utf32_char_constant: Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope()); ConsumeToken(); break; case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); ConsumeToken(); break; case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: case tok::utf8_string_literal: case tok::utf16_string_literal: case tok::utf32_string_literal: Res = ParseStringLiteralExpression(true); break; case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1] Res = ParseGenericSelectionExpression(); break; case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); case tok::plusplus: // unary-expression: '++' unary-expression [C99] case tok::minusminus: { // unary-expression: '--' unary-expression [C99] // C++ [expr.unary] has: // unary-expression: // ++ cast-expression // -- cast-expression SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(!getLangOpts().CPlusPlus); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } case tok::amp: { // unary-expression: '&' cast-expression // Special treatment because of member pointers SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false, true); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } case tok::star: // unary-expression: '*' cast-expression case tok::plus: // unary-expression: '+' cast-expression case tok::minus: // unary-expression: '-' cast-expression case tok::tilde: // unary-expression: '~' cast-expression case tok::exclaim: // unary-expression: '!' cast-expression case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression // unary-expression: 'sizeof' '(' type-name ')' case tok::kw_alignof: case tok::kw___alignof: // unary-expression: '__alignof' unary-expression // unary-expression: '__alignof' '(' type-name ')' // unary-expression: 'alignof' '(' type-id ')' case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier SourceLocation AmpAmpLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) return ExprError(Diag(Tok, diag::err_expected_ident)); if (getCurScope()->getFnParent() == 0) return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn)); Diag(AmpAmpLoc, diag::ext_gnu_address_of_label); LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), Tok.getLocation()); Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD); ConsumeToken(); return move(Res); } case tok::kw_const_cast: case tok::kw_dynamic_cast: case tok::kw_reinterpret_cast: case tok::kw_static_cast: Res = ParseCXXCasts(); break; case tok::kw_typeid: Res = ParseCXXTypeid(); break; case tok::kw___uuidof: Res = ParseCXXUuidof(); break; case tok::kw_this: Res = ParseCXXThis(); break; case tok::annot_typename: if (isStartOfObjCClassMessageMissingOpenBracket()) { ParsedType Type = getTypeAnnotation(Tok); // Fake up a Declarator to use with ActOnTypeName. DeclSpec DS(AttrFactory); DS.SetRangeStart(Tok.getLocation()); DS.SetRangeEnd(Tok.getLastLoc()); const char *PrevSpec = 0; unsigned DiagID; DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(), PrevSpec, DiagID, Type); Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); if (Ty.isInvalid()) break; ConsumeToken(); Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), Ty.get(), 0); break; } // Fall through case tok::annot_decltype: case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_bool: case tok::kw_short: case tok::kw_int: case tok::kw_long: case tok::kw___int64: case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: case tok::kw___vector: { if (!getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); } if (SavedKind == tok::kw_typename) { // postfix-expression: typename-specifier '(' expression-list[opt] ')' // typename-specifier braced-init-list if (TryAnnotateTypeOrScopeToken()) return ExprError(); } // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' // simple-type-specifier braced-init-list // DeclSpec DS(AttrFactory); ParseCXXSimpleTypeSpecifier(DS); if (Tok.isNot(tok::l_paren) && (!getLangOpts().CPlusPlus0x || Tok.isNot(tok::l_brace))) return ExprError(Diag(Tok, diag::err_expected_lparen_after_type) << DS.getSourceRange()); if (Tok.is(tok::l_brace)) Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Res = ParseCXXTypeConstructExpression(DS); break; } case tok::annot_cxxscope: { // [C++] id-expression: qualified-id // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. // (We can end up in this situation after tentative parsing.) if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::annot_cxxscope)) return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, isTypeCast); Token Next = NextToken(); if (Next.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); if (TemplateId->Kind == TNK_Type_template) { // We have a qualified template-id that we know refers to a // type, translate it into a type and continue parsing as a // cast expression. CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, isTypeCast); } } // Parse as an id-expression. Res = ParseCXXIdExpression(isAddressOfOperand); break; } case tok::annot_template_id: { // [C++] template-id TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Type_template) { // We have a template-id that we know refers to a type, // translate it into a type and continue parsing as a cast // expression. AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, isTypeCast); } // Fall through to treat the template-id as an id-expression. } case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id Res = ParseCXXIdExpression(isAddressOfOperand); break; case tok::coloncolon: { // ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken // annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::coloncolon)) return ParseCastExpression(isUnaryExpression, isAddressOfOperand); // ::new -> [C++] new-expression // ::delete -> [C++] delete-expression SourceLocation CCLoc = ConsumeToken(); if (Tok.is(tok::kw_new)) return ParseCXXNewExpression(true, CCLoc); if (Tok.is(tok::kw_delete)) return ParseCXXDeleteExpression(true, CCLoc); // This is not a type name or scope specifier, it is an invalid expression. Diag(CCLoc, diag::err_expected_expression); return ExprError(); } case tok::kw_new: // [C++] new-expression return ParseCXXNewExpression(false, Tok.getLocation()); case tok::kw_delete: // [C++] delete-expression return ParseCXXDeleteExpression(false, Tok.getLocation()); case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' Diag(Tok, diag::warn_cxx98_compat_noexcept_expr); SourceLocation KeyLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept")) return ExprError(); // C++11 [expr.unary.noexcept]p1: // The noexcept operator determines whether the evaluation of its operand, // which is an unevaluated operand, can throw an exception. EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); ExprResult Result = ParseExpression(); T.consumeClose(); if (!Result.isInvalid()) Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), Result.take(), T.getCloseLocation()); return move(Result); } case tok::kw___is_abstract: // [GNU] unary-type-trait case tok::kw___is_class: case tok::kw___is_empty: case tok::kw___is_enum: case tok::kw___is_literal: case tok::kw___is_arithmetic: case tok::kw___is_integral: case tok::kw___is_floating_point: case tok::kw___is_complete_type: case tok::kw___is_void: case tok::kw___is_array: case tok::kw___is_function: case tok::kw___is_reference: case tok::kw___is_lvalue_reference: case tok::kw___is_rvalue_reference: case tok::kw___is_fundamental: case tok::kw___is_object: case tok::kw___is_scalar: case tok::kw___is_compound: case tok::kw___is_pointer: case tok::kw___is_member_object_pointer: case tok::kw___is_member_function_pointer: case tok::kw___is_member_pointer: case tok::kw___is_const: case tok::kw___is_volatile: case tok::kw___is_standard_layout: case tok::kw___is_signed: case tok::kw___is_unsigned: case tok::kw___is_literal_type: case tok::kw___is_pod: case tok::kw___is_polymorphic: case tok::kw___is_trivial: case tok::kw___is_trivially_copyable: case tok::kw___is_union: case tok::kw___is_final: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: case tok::kw___has_trivial_destructor: case tok::kw___has_nothrow_assign: case tok::kw___has_nothrow_copy: case tok::kw___has_nothrow_constructor: case tok::kw___has_virtual_destructor: return ParseUnaryTypeTrait(); case tok::kw___builtin_types_compatible_p: case tok::kw___is_base_of: case tok::kw___is_same: case tok::kw___is_convertible: case tok::kw___is_convertible_to: case tok::kw___is_trivially_assignable: return ParseBinaryTypeTrait(); case tok::kw___is_trivially_constructible: return ParseTypeTrait(); case tok::kw___array_rank: case tok::kw___array_extent: return ParseArrayTypeTrait(); case tok::kw___is_lvalue_expr: case tok::kw___is_rvalue_expr: return ParseExpressionTrait(); case tok::at: { SourceLocation AtLoc = ConsumeToken(); return ParseObjCAtExpression(AtLoc); } case tok::caret: Res = ParseBlockLiteralExpression(); break; case tok::code_completion: { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); cutOffParsing(); return ExprError(); } case tok::l_square: if (getLangOpts().CPlusPlus0x) { if (getLangOpts().ObjC1) { // C++11 lambda expressions and Objective-C message sends both start with a // square bracket. There are three possibilities here: // we have a valid lambda expression, we have an invalid lambda // expression, or we have something that doesn't appear to be a lambda. // If we're in the last case, we fall back to ParseObjCMessageExpression. Res = TryParseLambdaExpression(); if (!Res.isInvalid() && !Res.get()) Res = ParseObjCMessageExpression(); break; } Res = ParseLambdaExpression(); break; } if (getLangOpts().ObjC1) { Res = ParseObjCMessageExpression(); break; } // FALL THROUGH. default: NotCastExpr = true; return ExprError(); } // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(Res); } /// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression /// is parsed, this method parses any suffixes that apply. /// /// postfix-expression: [C99 6.5.2] /// primary-expression /// postfix-expression '[' expression ']' /// postfix-expression '[' braced-init-list ']' /// postfix-expression '(' argument-expression-list[opt] ')' /// postfix-expression '.' identifier /// postfix-expression '->' identifier /// postfix-expression '++' /// postfix-expression '--' /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// /// argument-expression-list: [C99 6.5.2] /// argument-expression ...[opt] /// argument-expression-list ',' assignment-expression ...[opt] /// ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Now that the primary-expression piece of the postfix-expression has been // parsed, see if there are any postfix-expression pieces here. SourceLocation Loc; while (1) { switch (Tok.getKind()) { case tok::code_completion: if (InMessageExpression) return move(LHS); Actions.CodeCompletePostfixExpression(getCurScope(), LHS); cutOffParsing(); return ExprError(); case tok::identifier: // If we see identifier: after an expression, and we're not already in a // message send, then this is probably a message send with a missing // opening bracket '['. if (getLangOpts().ObjC1 && !InMessageExpression && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), ParsedType(), LHS.get()); break; } // Fall through; this isn't a message send. default: // Not a postfix-expression suffix. return move(LHS); case tok::l_square: { // postfix-expression: p-e '[' expression ']' // If we have a array postfix expression that starts on a new line and // Objective-C is enabled, it is highly likely that the user forgot a // semicolon after the base expression and that the array postfix-expr is // actually another message send. In this case, do some look-ahead to see // if the contents of the square brackets are obviously not a valid // expression and recover by pretending there is no suffix. if (getLangOpts().ObjC1 && Tok.isAtStartOfLine() && isSimpleObjCMessageExpression()) return move(LHS); // Reject array indices starting with a lambda-expression. '[[' is // reserved for attributes. if (CheckProhibitedCXX11Attribute()) return ExprError(); BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); Loc = T.getOpenLocation(); ExprResult Idx; if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Idx = ParseBraceInitializer(); } else Idx = ParseExpression(); SourceLocation RLoc = Tok.getLocation(); if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) { LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.take(), Loc, Idx.take(), RLoc); } else LHS = ExprError(); // Match the ']'. T.consumeClose(); break; } case tok::l_paren: // p-e: p-e '(' argument-expression-list[opt] ')' case tok::lesslessless: { // p-e: p-e '<<<' argument-expression-list '>>>' // '(' argument-expression-list[opt] ')' tok::TokenKind OpKind = Tok.getKind(); InMessageExpressionRAIIObject InMessage(*this, false); Expr *ExecConfig = 0; BalancedDelimiterTracker PT(*this, tok::l_paren); if (OpKind == tok::lesslessless) { ExprVector ExecConfigExprs(Actions); CommaLocsTy ExecConfigCommaLocs; SourceLocation OpenLoc = ConsumeToken(); if (ParseExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { LHS = ExprError(); } SourceLocation CloseLoc = Tok.getLocation(); if (Tok.is(tok::greatergreatergreater)) { ConsumeToken(); } else if (LHS.isInvalid()) { SkipUntil(tok::greatergreatergreater); } else { // There was an error closing the brackets Diag(Tok, diag::err_expected_ggg); Diag(OpenLoc, diag::note_matching) << "<<<"; SkipUntil(tok::greatergreatergreater); LHS = ExprError(); } if (!LHS.isInvalid()) { if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, "")) LHS = ExprError(); else Loc = PrevTokLocation; } if (!LHS.isInvalid()) { ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(), OpenLoc, move_arg(ExecConfigExprs), CloseLoc); if (ECResult.isInvalid()) LHS = ExprError(); else ExecConfig = ECResult.get(); } } else { PT.consumeOpen(); Loc = PT.getOpenLocation(); } ExprVector ArgExprs(Actions); CommaLocsTy CommaLocs; if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCall(getCurScope(), LHS.get(), llvm::ArrayRef()); cutOffParsing(); return ExprError(); } if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall, LHS.get())) { LHS = ExprError(); } } } // Match the ')'. if (LHS.isInvalid()) { SkipUntil(tok::r_paren); } else if (Tok.isNot(tok::r_paren)) { PT.consumeClose(); LHS = ExprError(); } else { assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc, move_arg(ArgExprs), Tok.getLocation(), ExecConfig); PT.consumeClose(); } break; } case tok::arrow: case tok::period: { // postfix-expression: p-e '->' template[opt] id-expression // postfix-expression: p-e '.' template[opt] id-expression tok::TokenKind OpKind = Tok.getKind(); SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. CXXScopeSpec SS; ParsedType ObjectType; bool MayBePseudoDestructor = false; if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), LHS.take(), OpLoc, OpKind, ObjectType, MayBePseudoDestructor); if (LHS.isInvalid()) break; ParseOptionalCXXScopeSpecifier(SS, ObjectType, /*EnteringContext=*/false, &MayBePseudoDestructor); if (SS.isNotEmpty()) ObjectType = ParsedType(); } if (Tok.is(tok::code_completion)) { // Code completion for a member access expression. Actions.CodeCompleteMemberReferenceExpr(getCurScope(), LHS.get(), OpLoc, OpKind == tok::arrow); cutOffParsing(); return ExprError(); } if (MayBePseudoDestructor && !LHS.isInvalid()) { LHS = ParseCXXPseudoDestructor(LHS.take(), OpLoc, OpKind, SS, ObjectType); break; } // Either the action has told is that this cannot be a // pseudo-destructor expression (based on the type of base // expression), or we didn't see a '~' in the right place. We // can still parse a destructor name here, but in that case it // names a real destructor. // Allow explicit constructor calls in Microsoft mode. // FIXME: Add support for explicit call of template constructor. SourceLocation TemplateKWLoc; UnqualifiedId Name; if (getLangOpts().ObjC2 && OpKind == tok::period && Tok.is(tok::kw_class)) { // Objective-C++: // After a '.' in a member access expression, treat the keyword // 'class' as if it were an identifier. // // This hack allows property access to the 'class' method because it is // such a common method name. For other C++ keywords that are // Objective-C method names, one must use the message send syntax. IdentifierInfo *Id = Tok.getIdentifierInfo(); SourceLocation Loc = ConsumeToken(); Name.setIdentifier(Id, Loc); } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/true, /*AllowConstructorName=*/ getLangOpts().MicrosoftExt, ObjectType, TemplateKWLoc, Name)) LHS = ExprError(); if (!LHS.isInvalid()) LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.take(), OpLoc, OpKind, SS, TemplateKWLoc, Name, CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : 0, Tok.is(tok::l_paren)); break; } case tok::plusplus: // postfix-expression: postfix-expression '++' case tok::minusminus: // postfix-expression: postfix-expression '--' if (!LHS.isInvalid()) { LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(), Tok.getKind(), LHS.take()); } ConsumeToken(); break; } } } /// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/ /// vec_step and we are at the start of an expression or a parenthesized /// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the /// expression (isCastExpr == false) or the type (isCastExpr == true). /// /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// /// [GNU] typeof-specifier: /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// /// [OpenCL 1.1 6.11.12] vec_step built-in function: /// vec_step ( expressions ) /// vec_step ( type-name ) /// ExprResult Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, bool &isCastExpr, ParsedType &CastTy, SourceRange &CastRange) { assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw_vec_step)) && "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; // If the operand doesn't start with an '(', it must be an expression. if (Tok.isNot(tok::l_paren)) { isCastExpr = false; if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) { Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo(); return ExprError(); } Operand = ParseCastExpression(true/*isUnaryExpression*/); } else { // If it starts with a '(', we know that it is either a parenthesized // type-name, or it is a unary-expression that starts with a compound // literal, or starts with a primary-expression that is a parenthesized // expression. ParenParseOption ExprType = CastExpr; SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, false, CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); // If ParseParenExpression parsed a '(typename)' sequence only, then this is // a type. if (ExprType == CastExpr) { isCastExpr = true; return ExprEmpty(); } if (getLangOpts().CPlusPlus || OpTok.isNot(tok::kw_typeof)) { // GNU typeof in C requires the expression to be parenthesized. Not so for // sizeof/alignof or in C++. Therefore, the parenthesized expression is // the start of a unary-expression, but doesn't include any postfix // pieces. Parse these now if present. if (!Operand.isInvalid()) Operand = ParsePostfixExpressionSuffix(Operand.get()); } } // If we get here, the operand to the typeof/sizeof/alignof was an expresion. isCastExpr = false; return move(Operand); } /// ParseUnaryExprOrTypeTraitExpression - Parse a sizeof or alignof expression. /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [C++0x] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) || Tok.is(tok::kw_alignof) || Tok.is(tok::kw_vec_step)) && "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); // [C++0x] 'sizeof' '...' '(' identifier ')' if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) { SourceLocation EllipsisLoc = ConsumeToken(); SourceLocation LParenLoc, RParenLoc; IdentifierInfo *Name = 0; SourceLocation NameLoc; if (Tok.is(tok::l_paren)) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); LParenLoc = T.getOpenLocation(); if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); T.consumeClose(); RParenLoc = T.getCloseLocation(); if (RParenLoc.isInvalid()) RParenLoc = PP.getLocForEndOfToken(NameLoc); } else { Diag(Tok, diag::err_expected_parameter_pack); SkipUntil(tok::r_paren); } } else if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); LParenLoc = PP.getLocForEndOfToken(EllipsisLoc); RParenLoc = PP.getLocForEndOfToken(NameLoc); Diag(LParenLoc, diag::err_paren_sizeof_parameter_pack) << Name << FixItHint::CreateInsertion(LParenLoc, "(") << FixItHint::CreateInsertion(RParenLoc, ")"); } else { Diag(Tok, diag::err_sizeof_parameter_pack); } if (!Name) return ExprError(); return Actions.ActOnSizeofParameterPackExpr(getCurScope(), OpTok.getLocation(), *Name, NameLoc, RParenLoc); } if (OpTok.is(tok::kw_alignof)) Diag(OpTok, diag::warn_cxx98_compat_alignof); EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); bool isCastExpr; ParsedType CastTy; SourceRange CastRange; ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange); UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof)) ExprKind = UETT_AlignOf; else if (OpTok.is(tok::kw_vec_step)) ExprKind = UETT_VecStep; if (isCastExpr) return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), ExprKind, /*isType=*/true, CastTy.getAsOpaquePtr(), CastRange); // If we get here, the operand to the sizeof/alignof was an expresion. if (!Operand.isInvalid()) Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), ExprKind, /*isType=*/false, Operand.release(), CastRange); return move(Operand); } /// ParseBuiltinPrimaryExpression /// /// primary-expression: [C99 6.5.1] /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')' /// /// [GNU] offsetof-member-designator: /// [GNU] identifier /// [GNU] offsetof-member-designator '.' identifier /// [GNU] offsetof-member-designator '[' expression ']' /// ExprResult Parser::ParseBuiltinPrimaryExpression() { ExprResult Res; const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); tok::TokenKind T = Tok.getKind(); SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier. // All of these start with an open paren. if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_lparen_after_id) << BuiltinII); BalancedDelimiterTracker PT(*this, tok::l_paren); PT.consumeOpen(); // TODO: Build AST. switch (T) { default: llvm_unreachable("Not a builtin primary expression!"); case tok::kw___builtin_va_arg: { ExprResult Expr(ParseAssignmentExpression()); if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) Expr = ExprError(); TypeResult Ty = ParseTypeName(); if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); Expr = ExprError(); } if (Expr.isInvalid() || Ty.isInvalid()) Res = ExprError(); else Res = Actions.ActOnVAArg(StartLoc, Expr.take(), Ty.get(), ConsumeParen()); break; } case tok::kw___builtin_offsetof: { SourceLocation TypeLoc = Tok.getLocation(); TypeResult Ty = ParseTypeName(); if (Ty.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprError(); // We must have at least one identifier here. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::r_paren); return ExprError(); } // Keep track of the various subcomponents we see. SmallVector Comps; Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = false; Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); // FIXME: This loop leaks the index expressions on error. while (1) { if (Tok.is(tok::period)) { // offsetof-member-designator: offsetof-member-designator '.' identifier Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = false; Comps.back().LocStart = ConsumeToken(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::r_paren); return ExprError(); } Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); Comps.back().LocEnd = ConsumeToken(); } else if (Tok.is(tok::l_square)) { if (CheckProhibitedCXX11Attribute()) return ExprError(); // offsetof-member-designator: offsetof-member-design '[' expression ']' Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = true; BalancedDelimiterTracker ST(*this, tok::l_square); ST.consumeOpen(); Comps.back().LocStart = ST.getOpenLocation(); Res = ParseExpression(); if (Res.isInvalid()) { SkipUntil(tok::r_paren); return move(Res); } Comps.back().U.E = Res.release(); ST.consumeClose(); Comps.back().LocEnd = ST.getCloseLocation(); } else { if (Tok.isNot(tok::r_paren)) { PT.consumeClose(); Res = ExprError(); } else if (Ty.isInvalid()) { Res = ExprError(); } else { PT.consumeClose(); Res = Actions.ActOnBuiltinOffsetOf(getCurScope(), StartLoc, TypeLoc, Ty.get(), &Comps[0], Comps.size(), PT.getCloseLocation()); } break; } } break; } case tok::kw___builtin_choose_expr: { ExprResult Cond(ParseAssignmentExpression()); if (Cond.isInvalid()) { SkipUntil(tok::r_paren); return move(Cond); } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprError(); ExprResult Expr1(ParseAssignmentExpression()); if (Expr1.isInvalid()) { SkipUntil(tok::r_paren); return move(Expr1); } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprError(); ExprResult Expr2(ParseAssignmentExpression()); if (Expr2.isInvalid()) { SkipUntil(tok::r_paren); return move(Expr2); } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); return ExprError(); } Res = Actions.ActOnChooseExpr(StartLoc, Cond.take(), Expr1.take(), Expr2.take(), ConsumeParen()); break; } case tok::kw___builtin_astype: { // The first argument is an expression to be converted, followed by a comma. ExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren)) return ExprError(); // Second argument is the type to bitcast to. TypeResult DestTy = ParseTypeName(); if (DestTy.isInvalid()) return ExprError(); // Attempt to consume the r-paren. if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); SkipUntil(tok::r_paren); return ExprError(); } Res = Actions.ActOnAsTypeExpr(Expr.take(), DestTy.get(), StartLoc, ConsumeParen()); break; } } if (Res.isInvalid()) return ExprError(); // These can be followed by postfix-expr pieces because they are // primary-expressions. return ParsePostfixExpressionSuffix(Res.take()); } /// ParseParenExpression - This parses the unit that starts with a '(' token, /// based on what is allowed by ExprType. The actual thing parsed is returned /// in ExprType. If stopIfCastExpr is true, it will only return the parsed type, /// not the parsed cast-expression. /// /// primary-expression: [C99 6.5.1] /// '(' expression ')' /// [GNU] '(' compound-statement ')' (if !ParenExprOnly) /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// cast-expression: [C99 6.5.4] /// '(' type-name ')' cast-expression /// [ARC] bridged-cast-expression /// /// [ARC] bridged-cast-expression: /// (__bridge type-name) cast-expression /// (__bridge_transfer type-name) cast-expression /// (__bridge_retained type-name) cast-expression ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, bool isTypeCast, ParsedType &CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) return ExprError(); SourceLocation OpenLoc = T.getOpenLocation(); ExprResult Result(true); bool isAmbiguousTypeId; CastTy = ParsedType(); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), ExprType >= CompoundLiteral? Sema::PCC_ParenthesizedExpression : Sema::PCC_Expression); cutOffParsing(); return ExprError(); } // Diagnose use of bridge casts in non-arc mode. bool BridgeCast = (getLangOpts().ObjC2 && (Tok.is(tok::kw___bridge) || Tok.is(tok::kw___bridge_transfer) || Tok.is(tok::kw___bridge_retained) || Tok.is(tok::kw___bridge_retain))); if (BridgeCast && !getLangOpts().ObjCAutoRefCount) { StringRef BridgeCastName = Tok.getName(); SourceLocation BridgeKeywordLoc = ConsumeToken(); if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc) << BridgeCastName << FixItHint::CreateReplacement(BridgeKeywordLoc, ""); BridgeCast = false; } // None of these cases should fall through with an invalid Result // unless they've already reported an error. if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); Actions.ActOnStartStmtExpr(); StmtResult Stmt(ParseCompoundStatement(true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. if (!Stmt.isInvalid()) { Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation()); } else { Actions.ActOnStmtExprError(); } } else if (ExprType >= CompoundLiteral && BridgeCast) { tok::TokenKind tokenKind = Tok.getKind(); SourceLocation BridgeKeywordLoc = ConsumeToken(); // Parse an Objective-C ARC ownership cast expression. ObjCBridgeCastKind Kind; if (tokenKind == tok::kw___bridge) Kind = OBC_Bridge; else if (tokenKind == tok::kw___bridge_transfer) Kind = OBC_BridgeTransfer; else if (tokenKind == tok::kw___bridge_retained) Kind = OBC_BridgeRetained; else { // As a hopefully temporary workaround, allow __bridge_retain as // a synonym for __bridge_retained, but only in system headers. assert(tokenKind == tok::kw___bridge_retain); Kind = OBC_BridgeRetained; if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) Diag(BridgeKeywordLoc, diag::err_arc_bridge_retain) << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge_retained"); } TypeResult Ty = ParseTypeName(); T.consumeClose(); RParenLoc = T.getCloseLocation(); ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false); if (Ty.isInvalid() || SubExpr.isInvalid()) return ExprError(); return Actions.ActOnObjCBridgedCast(getCurScope(), OpenLoc, Kind, BridgeKeywordLoc, Ty.get(), RParenLoc, SubExpr.get()); } else if (ExprType >= CompoundLiteral && isTypeIdInParens(isAmbiguousTypeId)) { // Otherwise, this is a compound literal expression or cast expression. // In C++, if the type-id is ambiguous we disambiguate based on context. // If stopIfCastExpr is true the context is a typeof/sizeof/alignof // in which case we should treat it as type-id. // if stopIfCastExpr is false, we need to determine the context past the // parens, so we defer to ParseCXXAmbiguousParenExpression for that. if (isAmbiguousTypeId && !stopIfCastExpr) { ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T); RParenLoc = T.getCloseLocation(); return res; } // Parse the type declarator. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParseDeclarator(DeclaratorInfo); // If our type is followed by an identifier and either ':' or ']', then // this is probably an Objective-C message send where the leading '[' is // missing. Recover as if that were the case. if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) && !InMessageExpression && getLangOpts().ObjC1 && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { TypeResult Ty; { InMessageExpressionRAIIObject InMessage(*this, false); Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } Result = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), Ty.get(), 0); } else { // Match the ')'. T.consumeClose(); RParenLoc = T.getCloseLocation(); if (Tok.is(tok::l_brace)) { ExprType = CompoundLiteral; TypeResult Ty; { InMessageExpressionRAIIObject InMessage(*this, false); Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); } if (ExprType == CastExpr) { // We parsed '(' type-name ')' and the thing after it wasn't a '{'. if (DeclaratorInfo.isInvalidType()) return ExprError(); // Note that this doesn't parse the subsequent cast-expression, it just // returns the parsed type to the callee. if (stopIfCastExpr) { TypeResult Ty; { InMessageExpressionRAIIObject InMessage(*this, false); Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } CastTy = Ty.get(); return ExprResult(); } // Reject the cast of super idiom in ObjC. if (Tok.is(tok::identifier) && getLangOpts().ObjC1 && Tok.getIdentifierInfo() == Ident_super && getCurScope()->isInObjcMethodScope() && GetLookAheadToken(1).isNot(tok::period)) { Diag(Tok.getLocation(), diag::err_illegal_super_cast) << SourceRange(OpenLoc, RParenLoc); return ExprError(); } // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. Result = ParseCastExpression(/*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, /*isTypeCast=*/IsTypeCast); if (!Result.isInvalid()) { Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, DeclaratorInfo, CastTy, RParenLoc, Result.take()); } return move(Result); } Diag(Tok, diag::err_expected_lbrace_in_compound_literal); return ExprError(); } } else if (isTypeCast) { // Parse the expression-list. InMessageExpressionRAIIObject InMessage(*this, false); ExprVector ArgExprs(Actions); CommaLocsTy CommaLocs; if (!ParseExpressionList(ArgExprs, CommaLocs)) { ExprType = SimpleExpr; Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), move_arg(ArgExprs)); } } else { InMessageExpressionRAIIObject InMessage(*this, false); Result = ParseExpression(MaybeTypeCast); ExprType = SimpleExpr; // Don't build a paren expression unless we actually match a ')'. if (!Result.isInvalid() && Tok.is(tok::r_paren)) Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.take()); } // Match the ')'. if (Result.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); } T.consumeClose(); RParenLoc = T.getCloseLocation(); return move(Result); } /// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name /// and we are at the left brace. /// /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// ExprResult Parser::ParseCompoundLiteralExpression(ParsedType Ty, SourceLocation LParenLoc, SourceLocation RParenLoc) { assert(Tok.is(tok::l_brace) && "Not a compound literal!"); if (!getLangOpts().C99) // Compound literals don't exist in C90. Diag(LParenLoc, diag::ext_c99_compound_literal); ExprResult Result = ParseInitializer(); if (!Result.isInvalid() && Ty) return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.take()); return move(Result); } /// ParseStringLiteralExpression - This handles the various token types that /// form string literals, and also handles string concatenation [C99 5.1.1.2, /// translation phase #6]. /// /// primary-expression: [C99 6.5.1] /// string-literal ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) { assert(isTokenStringLiteral() && "Not a string literal!"); // String concat. Note that keywords like __func__ and __FUNCTION__ are not // considered to be strings for concatenation purposes. SmallVector StringToks; do { StringToks.push_back(Tok); ConsumeStringToken(); } while (isTokenStringLiteral()); // Pass the set of string tokens, ready for concatenation, to the actions. return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size(), AllowUserDefinedLiteral ? getCurScope() : 0); } /// ParseGenericSelectionExpression - Parse a C11 generic-selection /// [C11 6.5.1.1]. /// /// generic-selection: /// _Generic ( assignment-expression , generic-assoc-list ) /// generic-assoc-list: /// generic-association /// generic-assoc-list , generic-association /// generic-association: /// type-name : assignment-expression /// default : assignment-expression ExprResult Parser::ParseGenericSelectionExpression() { assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected"); SourceLocation KeyLoc = ConsumeToken(); if (!getLangOpts().C11) Diag(KeyLoc, diag::ext_c11_generic_selection); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); ExprResult ControllingExpr; { // C11 6.5.1.1p3 "The controlling expression of a generic selection is // not evaluated." EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); ControllingExpr = ParseAssignmentExpression(); if (ControllingExpr.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); } } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) { SkipUntil(tok::r_paren); return ExprError(); } SourceLocation DefaultLoc; TypeVector Types(Actions); ExprVector Exprs(Actions); while (1) { ParsedType Ty; if (Tok.is(tok::kw_default)) { // C11 6.5.1.1p2 "A generic selection shall have no more than one default // generic association." if (!DefaultLoc.isInvalid()) { Diag(Tok, diag::err_duplicate_default_assoc); Diag(DefaultLoc, diag::note_previous_default_assoc); SkipUntil(tok::r_paren); return ExprError(); } DefaultLoc = ConsumeToken(); Ty = ParsedType(); } else { ColonProtectionRAIIObject X(*this); TypeResult TR = ParseTypeName(); if (TR.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); } Ty = TR.release(); } Types.push_back(Ty); if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) { SkipUntil(tok::r_paren); return ExprError(); } // FIXME: These expressions should be parsed in a potentially potentially // evaluated context. ExprResult ER(ParseAssignmentExpression()); if (ER.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); } Exprs.push_back(ER.release()); if (Tok.isNot(tok::comma)) break; ConsumeToken(); } T.consumeClose(); if (T.getCloseLocation().isInvalid()) return ExprError(); return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, T.getCloseLocation(), ControllingExpr.release(), move_arg(Types), move_arg(Exprs)); } /// ParseExpressionList - Used for C/C++ (argument-)expression-list. /// /// argument-expression-list: /// assignment-expression /// argument-expression-list , assignment-expression /// /// [C++] expression-list: /// [C++] assignment-expression /// [C++] expression-list , assignment-expression /// /// [C++0x] expression-list: /// [C++0x] initializer-list /// /// [C++0x] initializer-list /// [C++0x] initializer-clause ...[opt] /// [C++0x] initializer-list , initializer-clause ...[opt] /// /// [C++0x] initializer-clause: /// [C++0x] assignment-expression /// [C++0x] braced-init-list /// bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, SmallVectorImpl &CommaLocs, void (Sema::*Completer)(Scope *S, Expr *Data, llvm::ArrayRef Args), Expr *Data) { while (1) { if (Tok.is(tok::code_completion)) { if (Completer) (Actions.*Completer)(getCurScope(), Data, Exprs); else Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); cutOffParsing(); return true; } ExprResult Expr; if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Expr = ParseBraceInitializer(); } else Expr = ParseAssignmentExpression(); if (Tok.is(tok::ellipsis)) Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); if (Expr.isInvalid()) return true; Exprs.push_back(Expr.release()); if (Tok.isNot(tok::comma)) return false; // Move to the next argument, remember where the comma was. CommaLocs.push_back(ConsumeToken()); } } /// ParseBlockId - Parse a block-id, which roughly looks like int (int x). /// /// [clang] block-id: /// [clang] specifier-qualifier-list block-declarator /// void Parser::ParseBlockId() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); return cutOffParsing(); } // Parse the specifier-qualifier-list piece. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // Parse the block-declarator. Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext); ParseDeclarator(DeclaratorInfo); // We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes. DeclaratorInfo.takeAttributes(DS.getAttributes(), SourceLocation()); MaybeParseGNUAttributes(DeclaratorInfo); // Inform sema that we are starting a block. Actions.ActOnBlockArguments(DeclaratorInfo, getCurScope()); } /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks /// like ^(int x){ return x+1; } /// /// block-literal: /// [clang] '^' block-args[opt] compound-statement /// [clang] '^' block-id compound-statement /// [clang] block-args: /// [clang] '(' parameter-list ')' /// ExprResult Parser::ParseBlockLiteralExpression() { assert(Tok.is(tok::caret) && "block literal starts with ^"); SourceLocation CaretLoc = ConsumeToken(); PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc, "block literal parsing"); // Enter a scope to hold everything within the block. This includes the // argument decls, decls within the compound expression, etc. This also // allows determining whether a variable reference inside the block is // within or outside of the block. ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope | Scope::DeclScope); // Inform sema that we are starting a block. Actions.ActOnBlockStart(CaretLoc, getCurScope()); // Parse the return type if present. DeclSpec DS(AttrFactory); Declarator ParamInfo(DS, Declarator::BlockLiteralContext); // FIXME: Since the return type isn't actually parsed, it can't be used to // fill ParamInfo with an initial valid range, so do it manually. ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation())); // If this block has arguments, parse them. There is no ambiguity here with // the expression case, because the expression case requires a parameter list. if (Tok.is(tok::l_paren)) { ParseParenDeclarator(ParamInfo); // Parse the pieces after the identifier as if we had "int(...)". // SetIdentifier sets the source range end, but in this case we're past // that location. SourceLocation Tmp = ParamInfo.getSourceRange().getEnd(); ParamInfo.SetIdentifier(0, CaretLoc); ParamInfo.SetRangeEnd(Tmp); if (ParamInfo.isInvalidType()) { // If there was an error parsing the arguments, they may have // tried to use ^(x+y) which requires an argument list. Just // skip the whole block literal. Actions.ActOnBlockError(CaretLoc, getCurScope()); return ExprError(); } MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. Actions.ActOnBlockArguments(ParamInfo, getCurScope()); } else if (!Tok.is(tok::l_brace)) { ParseBlockId(); } else { // Otherwise, pretend we saw (void). ParsedAttributes attrs(AttrFactory); ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, SourceLocation(), 0, 0, 0, true, SourceLocation(), SourceLocation(), SourceLocation(), SourceLocation(), EST_None, SourceLocation(), - 0, 0, 0, 0, 0, + 0, 0, 0, 0, CaretLoc, CaretLoc, ParamInfo), attrs, CaretLoc); MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. Actions.ActOnBlockArguments(ParamInfo, getCurScope()); } ExprResult Result(true); if (!Tok.is(tok::l_brace)) { // Saw something like: ^expr Diag(Tok, diag::err_expected_expression); Actions.ActOnBlockError(CaretLoc, getCurScope()); return ExprError(); } StmtResult Stmt(ParseCompoundStatementBody()); BlockScope.Exit(); if (!Stmt.isInvalid()) Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope()); else Actions.ActOnBlockError(CaretLoc, getCurScope()); return move(Result); } /// ParseObjCBoolLiteral - This handles the objective-c Boolean literals. /// /// '__objc_yes' /// '__objc_no' ExprResult Parser::ParseObjCBoolLiteral() { tok::TokenKind Kind = Tok.getKind(); return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind); } Index: vendor/clang/dist/lib/Parse/ParseExprCXX.cpp =================================================================== --- vendor/clang/dist/lib/Parse/ParseExprCXX.cpp (revision 235808) +++ vendor/clang/dist/lib/Parse/ParseExprCXX.cpp (revision 235809) @@ -1,2851 +1,2846 @@ //===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===// // // 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 Expression parsing implementation for C++. // //===----------------------------------------------------------------------===// #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; static int SelectDigraphErrorMessage(tok::TokenKind Kind) { switch (Kind) { case tok::kw_template: return 0; case tok::kw_const_cast: return 1; case tok::kw_dynamic_cast: return 2; case tok::kw_reinterpret_cast: return 3; case tok::kw_static_cast: return 4; default: llvm_unreachable("Unknown type for digraph error message."); } } // Are the two tokens adjacent in the same source file? static bool AreTokensAdjacent(Preprocessor &PP, Token &First, Token &Second) { SourceManager &SM = PP.getSourceManager(); SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation()); SourceLocation FirstEnd = FirstLoc.getLocWithOffset(First.getLength()); return FirstEnd == SM.getSpellingLoc(Second.getLocation()); } // Suggest fixit for "<::" after a cast. static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken, Token &ColonToken, tok::TokenKind Kind, bool AtDigraph) { // Pull '<:' and ':' off token stream. if (!AtDigraph) PP.Lex(DigraphToken); PP.Lex(ColonToken); SourceRange Range; Range.setBegin(DigraphToken.getLocation()); Range.setEnd(ColonToken.getLocation()); P.Diag(DigraphToken.getLocation(), diag::err_missing_whitespace_digraph) << SelectDigraphErrorMessage(Kind) << FixItHint::CreateReplacement(Range, "< ::"); // Update token information to reflect their change in token type. ColonToken.setKind(tok::coloncolon); ColonToken.setLocation(ColonToken.getLocation().getLocWithOffset(-1)); ColonToken.setLength(2); DigraphToken.setKind(tok::less); DigraphToken.setLength(1); // Push new tokens back to token stream. PP.EnterToken(ColonToken); if (!AtDigraph) PP.EnterToken(DigraphToken); } // Check for '<::' which should be '< ::' instead of '[:' when following // a template name. void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, bool EnteringContext, IdentifierInfo &II, CXXScopeSpec &SS) { if (!Next.is(tok::l_square) || Next.getLength() != 2) return; Token SecondToken = GetLookAheadToken(2); if (!SecondToken.is(tok::colon) || !AreTokensAdjacent(PP, Next, SecondToken)) return; TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); bool MemberOfUnknownSpecialization; if (!Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false, TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization)) return; FixDigraph(*this, PP, Next, SecondToken, tok::kw_template, /*AtDigraph*/false); } /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which /// may be preceded by '::'). Note that this routine will not parse ::new or /// ::delete; it will just leave them in the token stream. /// /// '::'[opt] nested-name-specifier /// '::' /// /// nested-name-specifier: /// type-name '::' /// namespace-name '::' /// nested-name-specifier identifier '::' /// nested-name-specifier 'template'[opt] simple-template-id '::' /// /// /// \param SS the scope specifier that will be set to the parsed /// nested-name-specifier (or empty) /// /// \param ObjectType if this nested-name-specifier is being parsed following /// the "." or "->" of a member access expression, this parameter provides the /// type of the object whose members are being accessed. /// /// \param EnteringContext whether we will be entering into the context of /// the nested-name-specifier after parsing it. /// /// \param MayBePseudoDestructor When non-NULL, points to a flag that /// indicates whether this nested-name-specifier may be part of a /// pseudo-destructor name. In this case, the flag will be set false /// if we don't actually end up parsing a destructor name. Moreorover, /// if we do end up determining that we are parsing a destructor name, /// the last component of the nested-name-specifier is not parsed as /// part of the scope specifier. /// member access expression, e.g., the \p T:: in \p p->T::m. /// /// \returns true if there was an error parsing a scope specifier bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); ConsumeToken(); return false; } bool HasScopeSpecifier = false; if (Tok.is(tok::coloncolon)) { // ::new and ::delete aren't nested-name-specifiers. tok::TokenKind NextKind = NextToken().getKind(); if (NextKind == tok::kw_new || NextKind == tok::kw_delete) return false; // '::' - Global scope qualifier. if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS)) return true; HasScopeSpecifier = true; } bool CheckForDestructor = false; if (MayBePseudoDestructor && *MayBePseudoDestructor) { CheckForDestructor = true; *MayBePseudoDestructor = false; } if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) { DeclSpec DS(AttrFactory); SourceLocation DeclLoc = Tok.getLocation(); SourceLocation EndLoc = ParseDecltypeSpecifier(DS); if (Tok.isNot(tok::coloncolon)) { AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc); return false; } SourceLocation CCLoc = ConsumeToken(); if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc)) SS.SetInvalid(SourceRange(DeclLoc, CCLoc)); HasScopeSpecifier = true; } while (true) { if (HasScopeSpecifier) { // C++ [basic.lookup.classref]p5: // If the qualified-id has the form // // ::class-name-or-namespace-name::... // // the class-name-or-namespace-name is looked up in global scope as a // class-name or namespace-name. // // To implement this, we clear out the object type as soon as we've // seen a leading '::' or part of a nested-name-specifier. ObjectType = ParsedType(); if (Tok.is(tok::code_completion)) { // Code completion for a nested-name-specifier, where the code // code completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext); // Include code completion token into the range of the scope otherwise // when we try to annotate the scope tokens the dangling code completion // token will cause assertion in // Preprocessor::AnnotatePreviousCachedTokens. SS.setEndLoc(Tok.getLocation()); cutOffParsing(); return true; } } // nested-name-specifier: // nested-name-specifier 'template'[opt] simple-template-id '::' // Parse the optional 'template' keyword, then make sure we have // 'identifier <' after it. if (Tok.is(tok::kw_template)) { // If we don't have a scope specifier or an object type, this isn't a // nested-name-specifier, since they aren't allowed to start with // 'template'. if (!HasScopeSpecifier && !ObjectType) break; TentativeParsingAction TPA(*this); SourceLocation TemplateKWLoc = ConsumeToken(); UnqualifiedId TemplateName; if (Tok.is(tok::identifier)) { // Consume the identifier. TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); } else if (Tok.is(tok::kw_operator)) { if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, TemplateName)) { TPA.Commit(); break; } if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId && TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) { Diag(TemplateName.getSourceRange().getBegin(), diag::err_id_after_template_in_nested_name_spec) << TemplateName.getSourceRange(); TPA.Commit(); break; } } else { TPA.Revert(); break; } // If the next token is not '<', we have a qualified-id that refers // to a template name, such as T::template apply, but is not a // template-id. if (Tok.isNot(tok::less)) { TPA.Revert(); break; } // Commit to parsing the template-id. TPA.Commit(); TemplateTy Template; if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, EnteringContext, Template)) { if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, TemplateName, false)) return true; } else return true; continue; } if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) { // We have // // simple-template-id '::' // // So we need to check whether the simple-template-id is of the // right kind (it should name a type or be dependent), and then // convert it into a type within the nested-name-specifier. TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { *MayBePseudoDestructor = true; return false; } // Consume the template-id token. ConsumeToken(); assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); HasScopeSpecifier = true; ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), TemplateId->NumArgs); if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, CCLoc, EnteringContext)) { SourceLocation StartLoc = SS.getBeginLoc().isValid()? SS.getBeginLoc() : TemplateId->TemplateNameLoc; SS.SetInvalid(SourceRange(StartLoc, CCLoc)); } continue; } // The rest of the nested-name-specifier possibilities start with // tok::identifier. if (Tok.isNot(tok::identifier)) break; IdentifierInfo &II = *Tok.getIdentifierInfo(); // nested-name-specifier: // type-name '::' // namespace-name '::' // nested-name-specifier identifier '::' Token Next = NextToken(); // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover // and emit a fixit hint for it. if (Next.is(tok::colon) && !ColonIsSacred) { if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, II, Tok.getLocation(), Next.getLocation(), ObjectType, EnteringContext) && // If the token after the colon isn't an identifier, it's still an // error, but they probably meant something else strange so don't // recover like this. PP.LookAhead(1).is(tok::identifier)) { Diag(Next, diag::err_unexected_colon_in_nested_name_spec) << FixItHint::CreateReplacement(Next.getLocation(), "::"); // Recover as if the user wrote '::'. Next.setKind(tok::coloncolon); } } if (Next.is(tok::coloncolon)) { if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && !Actions.isNonTypeNestedNameSpecifier(getCurScope(), SS, Tok.getLocation(), II, ObjectType)) { *MayBePseudoDestructor = true; return false; } // We have an identifier followed by a '::'. Lookup this name // as the name in a nested-name-specifier. SourceLocation IdLoc = ConsumeToken(); assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) && "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); HasScopeSpecifier = true; if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc, ObjectType, EnteringContext, SS)) SS.SetInvalid(SourceRange(IdLoc, CCLoc)); continue; } CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS); // nested-name-specifier: // type-name '<' if (Next.is(tok::less)) { TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); bool MemberOfUnknownSpecialization; if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false, TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization)) { // We have found a template name, so annotate this token // with a template-id annotation. We do not permit the // template-id to be translated into a type annotation, // because some clients (e.g., the parsing of class template // specializations) still want to see the original template-id // token. ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), TemplateName, false)) return true; continue; } if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && (IsTypename || IsTemplateArgumentList(1))) { // We have something like t::getAs, where getAs is a // member of an unknown specialization. However, this will only // parse correctly as a template, so suggest the keyword 'template' // before 'getAs' and treat this as a dependent template name. unsigned DiagID = diag::err_missing_dependent_template_keyword; if (getLangOpts().MicrosoftExt) DiagID = diag::warn_missing_dependent_template_keyword; Diag(Tok.getLocation(), DiagID) << II.getName() << FixItHint::CreateInsertion(Tok.getLocation(), "template "); if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, SourceLocation(), TemplateName, ObjectType, EnteringContext, Template)) { // Consume the identifier. ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), TemplateName, false)) return true; } else return true; continue; } } // We don't have any tokens that form the beginning of a // nested-name-specifier, so we're done. break; } // Even if we didn't see any pieces of a nested-name-specifier, we // still check whether there is a tilde in this position, which // indicates a potential pseudo-destructor. if (CheckForDestructor && Tok.is(tok::tilde)) *MayBePseudoDestructor = true; return false; } /// ParseCXXIdExpression - Handle id-expression. /// /// id-expression: /// unqualified-id /// qualified-id /// /// qualified-id: /// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id /// '::' identifier /// '::' operator-function-id /// '::' template-id /// /// NOTE: The standard specifies that, for qualified-id, the parser does not /// expect: /// /// '::' conversion-function-id /// '::' '~' class-name /// /// This may cause a slight inconsistency on diagnostics: /// /// class C {}; /// namespace A {} /// void f() { /// :: A :: ~ C(); // Some Sema error about using destructor with a /// // namespace. /// :: ~ C(); // Some Parser error like 'unexpected ~'. /// } /// /// We simplify the parser a bit and make it work like: /// /// qualified-id: /// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id /// '::' unqualified-id /// /// That way Sema can handle and report similar errors for namespaces and the /// global scope. /// /// The isAddressOfOperand parameter indicates that this id-expression is a /// direct operand of the address-of operator. This is, besides member contexts, /// the only place where a qualified-id naming a non-static class member may /// appear. /// ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // qualified-id: // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id // '::' unqualified-id // CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); SourceLocation TemplateKWLoc; UnqualifiedId Name; if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, /*ObjectType=*/ ParsedType(), TemplateKWLoc, Name)) return ExprError(); // This is only the direct operand of an & operator if it is not // followed by a postfix-expression suffix. if (isAddressOfOperand && isPostfixExpressionSuffixStart()) isAddressOfOperand = false; return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren), isAddressOfOperand); } /// ParseLambdaExpression - Parse a C++0x lambda expression. /// /// lambda-expression: /// lambda-introducer lambda-declarator[opt] compound-statement /// /// lambda-introducer: /// '[' lambda-capture[opt] ']' /// /// lambda-capture: /// capture-default /// capture-list /// capture-default ',' capture-list /// /// capture-default: /// '&' /// '=' /// /// capture-list: /// capture /// capture-list ',' capture /// /// capture: /// identifier /// '&' identifier /// 'this' /// /// lambda-declarator: /// '(' parameter-declaration-clause ')' attribute-specifier[opt] /// 'mutable'[opt] exception-specification[opt] /// trailing-return-type[opt] /// ExprResult Parser::ParseLambdaExpression() { // Parse lambda-introducer. LambdaIntroducer Intro; llvm::Optional DiagID(ParseLambdaIntroducer(Intro)); if (DiagID) { Diag(Tok, DiagID.getValue()); SkipUntil(tok::r_square); SkipUntil(tok::l_brace); SkipUntil(tok::r_brace); return ExprError(); } return ParseLambdaExpressionAfterIntroducer(Intro); } /// TryParseLambdaExpression - Use lookahead and potentially tentative /// parsing to determine if we are looking at a C++0x lambda expression, and parse /// it if we are. /// /// If we are not looking at a lambda expression, returns ExprError(). ExprResult Parser::TryParseLambdaExpression() { assert(getLangOpts().CPlusPlus0x && Tok.is(tok::l_square) && "Not at the start of a possible lambda expression."); const Token Next = NextToken(), After = GetLookAheadToken(2); // If lookahead indicates this is a lambda... if (Next.is(tok::r_square) || // [] Next.is(tok::equal) || // [= (Next.is(tok::amp) && // [&] or [&, (After.is(tok::r_square) || After.is(tok::comma))) || (Next.is(tok::identifier) && // [identifier] After.is(tok::r_square))) { return ParseLambdaExpression(); } // If lookahead indicates an ObjC message send... // [identifier identifier if (Next.is(tok::identifier) && After.is(tok::identifier)) { return ExprEmpty(); } // Here, we're stuck: lambda introducers and Objective-C message sends are // unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of // writing two routines to parse a lambda introducer, just try to parse // a lambda introducer first, and fall back if that fails. // (TryParseLambdaIntroducer never produces any diagnostic output.) LambdaIntroducer Intro; if (TryParseLambdaIntroducer(Intro)) return ExprEmpty(); return ParseLambdaExpressionAfterIntroducer(Intro); } /// ParseLambdaExpression - Parse a lambda introducer. /// /// Returns a DiagnosticID if it hit something unexpected. llvm::Optional Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){ typedef llvm::Optional DiagResult; assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['."); BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); Intro.Range.setBegin(T.getOpenLocation()); bool first = true; // Parse capture-default. if (Tok.is(tok::amp) && (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) { Intro.Default = LCD_ByRef; Intro.DefaultLoc = ConsumeToken(); first = false; } else if (Tok.is(tok::equal)) { Intro.Default = LCD_ByCopy; Intro.DefaultLoc = ConsumeToken(); first = false; } while (Tok.isNot(tok::r_square)) { if (!first) { if (Tok.isNot(tok::comma)) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/false); ConsumeCodeCompletionToken(); break; } return DiagResult(diag::err_expected_comma_or_rsquare); } ConsumeToken(); } if (Tok.is(tok::code_completion)) { // If we're in Objective-C++ and we have a bare '[', then this is more // likely to be a message receiver. if (getLangOpts().ObjC1 && first) Actions.CodeCompleteObjCMessageReceiver(getCurScope()); else Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/false); ConsumeCodeCompletionToken(); break; } first = false; // Parse capture. LambdaCaptureKind Kind = LCK_ByCopy; SourceLocation Loc; IdentifierInfo* Id = 0; SourceLocation EllipsisLoc; if (Tok.is(tok::kw_this)) { Kind = LCK_This; Loc = ConsumeToken(); } else { if (Tok.is(tok::amp)) { Kind = LCK_ByRef; ConsumeToken(); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/true); ConsumeCodeCompletionToken(); break; } } if (Tok.is(tok::identifier)) { Id = Tok.getIdentifierInfo(); Loc = ConsumeToken(); if (Tok.is(tok::ellipsis)) EllipsisLoc = ConsumeToken(); } else if (Tok.is(tok::kw_this)) { // FIXME: If we want to suggest a fixit here, will need to return more // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be // Clear()ed to prevent emission in case of tentative parsing? return DiagResult(diag::err_this_captured_by_reference); } else { return DiagResult(diag::err_expected_capture); } } Intro.addCapture(Kind, Loc, Id, EllipsisLoc); } T.consumeClose(); Intro.Range.setEnd(T.getCloseLocation()); return DiagResult(); } /// TryParseLambdaIntroducer - Tentatively parse a lambda introducer. /// /// Returns true if it hit something unexpected. bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { TentativeParsingAction PA(*this); llvm::Optional DiagID(ParseLambdaIntroducer(Intro)); if (DiagID) { PA.Revert(); return true; } PA.Commit(); return false; } /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda /// expression. ExprResult Parser::ParseLambdaExpressionAfterIntroducer( LambdaIntroducer &Intro) { SourceLocation LambdaBeginLoc = Intro.Range.getBegin(); Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda); PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc, "lambda expression parsing"); // Parse lambda-declarator[opt]. DeclSpec DS(AttrFactory); Declarator D(DS, Declarator::LambdaExprContext); if (Tok.is(tok::l_paren)) { ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | Scope::DeclScope); SourceLocation DeclLoc, DeclEndLoc; BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); DeclLoc = T.getOpenLocation(); // Parse parameter-declaration-clause. ParsedAttributes Attr(AttrFactory); llvm::SmallVector ParamInfo; SourceLocation EllipsisLoc; if (Tok.isNot(tok::r_paren)) ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); T.consumeClose(); DeclEndLoc = T.getCloseLocation(); // Parse 'mutable'[opt]. SourceLocation MutableLoc; if (Tok.is(tok::kw_mutable)) { MutableLoc = ConsumeToken(); DeclEndLoc = MutableLoc; } // Parse exception-specification[opt]. ExceptionSpecificationType ESpecType = EST_None; SourceRange ESpecRange; llvm::SmallVector DynamicExceptions; llvm::SmallVector DynamicExceptionRanges; ExprResult NoexceptExpr; - CachedTokens *ExceptionSpecTokens; - ESpecType = tryParseExceptionSpecification(/*Delayed=*/false, - ESpecRange, + ESpecType = tryParseExceptionSpecification(ESpecRange, DynamicExceptions, DynamicExceptionRanges, - NoexceptExpr, - ExceptionSpecTokens); + NoexceptExpr); if (ESpecType != EST_None) DeclEndLoc = ESpecRange.getEnd(); // Parse attribute-specifier[opt]. MaybeParseCXX0XAttributes(Attr, &DeclEndLoc); // Parse trailing-return-type[opt]. ParsedType TrailingReturnType; if (Tok.is(tok::arrow)) { SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range).get(); if (Range.getEnd().isValid()) DeclEndLoc = Range.getEnd(); } PrototypeScope.Exit(); D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isVariadic=*/EllipsisLoc.isValid(), EllipsisLoc, ParamInfo.data(), ParamInfo.size(), DS.getTypeQualifiers(), /*RefQualifierIsLValueRef=*/true, /*RefQualifierLoc=*/SourceLocation(), /*ConstQualifierLoc=*/SourceLocation(), /*VolatileQualifierLoc=*/SourceLocation(), MutableLoc, ESpecType, ESpecRange.getBegin(), DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, - 0, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow)) { // It's common to forget that one needs '()' before 'mutable' or the // result type. Deal with this. Diag(Tok, diag::err_lambda_missing_parens) << Tok.is(tok::arrow) << FixItHint::CreateInsertion(Tok.getLocation(), "() "); SourceLocation DeclLoc = Tok.getLocation(); SourceLocation DeclEndLoc = DeclLoc; // Parse 'mutable', if it's there. SourceLocation MutableLoc; if (Tok.is(tok::kw_mutable)) { MutableLoc = ConsumeToken(); DeclEndLoc = MutableLoc; } // Parse the return type, if there is one. ParsedType TrailingReturnType; if (Tok.is(tok::arrow)) { SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range).get(); if (Range.getEnd().isValid()) DeclEndLoc = Range.getEnd(); } ParsedAttributes Attr(AttrFactory); D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isVariadic=*/false, /*EllipsisLoc=*/SourceLocation(), /*Params=*/0, /*NumParams=*/0, /*TypeQuals=*/0, /*RefQualifierIsLValueRef=*/true, /*RefQualifierLoc=*/SourceLocation(), /*ConstQualifierLoc=*/SourceLocation(), /*VolatileQualifierLoc=*/SourceLocation(), MutableLoc, EST_None, /*ESpecLoc=*/SourceLocation(), /*Exceptions=*/0, /*ExceptionRanges=*/0, /*NumExceptions=*/0, /*NoexceptExpr=*/0, - /*ExceptionSpecTokens=*/0, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); } // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope; ParseScope BodyScope(this, ScopeFlags); Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); // Parse compound-statement. if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected_lambda_body); Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); return ExprError(); } StmtResult Stmt(ParseCompoundStatementBody()); BodyScope.Exit(); if (!Stmt.isInvalid()) return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(), getCurScope()); Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); return ExprError(); } /// ParseCXXCasts - This handles the various ways to cast expressions to another /// type. /// /// postfix-expression: [C++ 5.2p1] /// 'dynamic_cast' '<' type-name '>' '(' expression ')' /// 'static_cast' '<' type-name '>' '(' expression ')' /// 'reinterpret_cast' '<' type-name '>' '(' expression ')' /// 'const_cast' '<' type-name '>' '(' expression ')' /// ExprResult Parser::ParseCXXCasts() { tok::TokenKind Kind = Tok.getKind(); const char *CastName = 0; // For error messages switch (Kind) { default: llvm_unreachable("Unknown C++ cast!"); case tok::kw_const_cast: CastName = "const_cast"; break; case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break; case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break; case tok::kw_static_cast: CastName = "static_cast"; break; } SourceLocation OpLoc = ConsumeToken(); SourceLocation LAngleBracketLoc = Tok.getLocation(); // Check for "<::" which is parsed as "[:". If found, fix token stream, // diagnose error, suggest fix, and recover parsing. Token Next = NextToken(); if (Tok.is(tok::l_square) && Tok.getLength() == 2 && Next.is(tok::colon) && AreTokensAdjacent(PP, Tok, Next)) FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true); if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName)) return ExprError(); // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // Parse the abstract-declarator, if present. Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParseDeclarator(DeclaratorInfo); SourceLocation RAngleBracketLoc = Tok.getLocation(); if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<"); SourceLocation LParenLoc, RParenLoc; BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen_after, CastName)) return ExprError(); ExprResult Result = ParseExpression(); // Match the ')'. T.consumeClose(); if (!Result.isInvalid() && !DeclaratorInfo.isInvalidType()) Result = Actions.ActOnCXXNamedCast(OpLoc, Kind, LAngleBracketLoc, DeclaratorInfo, RAngleBracketLoc, T.getOpenLocation(), Result.take(), T.getCloseLocation()); return move(Result); } /// ParseCXXTypeid - This handles the C++ typeid expression. /// /// postfix-expression: [C++ 5.2p1] /// 'typeid' '(' expression ')' /// 'typeid' '(' type-id ')' /// ExprResult Parser::ParseCXXTypeid() { assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!"); SourceLocation OpLoc = ConsumeToken(); SourceLocation LParenLoc, RParenLoc; BalancedDelimiterTracker T(*this, tok::l_paren); // typeid expressions are always parenthesized. if (T.expectAndConsume(diag::err_expected_lparen_after, "typeid")) return ExprError(); LParenLoc = T.getOpenLocation(); ExprResult Result; if (isTypeIdInParens()) { TypeResult Ty = ParseTypeName(); // Match the ')'. T.consumeClose(); RParenLoc = T.getCloseLocation(); if (Ty.isInvalid() || RParenLoc.isInvalid()) return ExprError(); Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true, Ty.get().getAsOpaquePtr(), RParenLoc); } else { // C++0x [expr.typeid]p3: // When typeid is applied to an expression other than an lvalue of a // polymorphic class type [...] The expression is an unevaluated // operand (Clause 5). // // Note that we can't tell whether the expression is an lvalue of a // polymorphic class type until after we've parsed the expression; we // speculatively assume the subexpression is unevaluated, and fix it up // later. EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); Result = ParseExpression(); // Match the ')'. if (Result.isInvalid()) SkipUntil(tok::r_paren); else { T.consumeClose(); RParenLoc = T.getCloseLocation(); if (RParenLoc.isInvalid()) return ExprError(); Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false, Result.release(), RParenLoc); } } return move(Result); } /// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression. /// /// '__uuidof' '(' expression ')' /// '__uuidof' '(' type-id ')' /// ExprResult Parser::ParseCXXUuidof() { assert(Tok.is(tok::kw___uuidof) && "Not '__uuidof'!"); SourceLocation OpLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); // __uuidof expressions are always parenthesized. if (T.expectAndConsume(diag::err_expected_lparen_after, "__uuidof")) return ExprError(); ExprResult Result; if (isTypeIdInParens()) { TypeResult Ty = ParseTypeName(); // Match the ')'. T.consumeClose(); if (Ty.isInvalid()) return ExprError(); Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), /*isType=*/true, Ty.get().getAsOpaquePtr(), T.getCloseLocation()); } else { EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); Result = ParseExpression(); // Match the ')'. if (Result.isInvalid()) SkipUntil(tok::r_paren); else { T.consumeClose(); Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), /*isType=*/false, Result.release(), T.getCloseLocation()); } } return move(Result); } /// \brief Parse a C++ pseudo-destructor expression after the base, /// . or -> operator, and nested-name-specifier have already been /// parsed. /// /// postfix-expression: [C++ 5.2] /// postfix-expression . pseudo-destructor-name /// postfix-expression -> pseudo-destructor-name /// /// pseudo-destructor-name: /// ::[opt] nested-name-specifier[opt] type-name :: ~type-name /// ::[opt] nested-name-specifier template simple-template-id :: /// ~type-name /// ::[opt] nested-name-specifier[opt] ~type-name /// ExprResult Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, ParsedType ObjectType) { // We're parsing either a pseudo-destructor-name or a dependent // member access that has the same form as a // pseudo-destructor-name. We parse both in the same way and let // the action model sort them out. // // Note that the ::[opt] nested-name-specifier[opt] has already // been parsed, and if there was a simple-template-id, it has // been coalesced into a template-id annotation token. UnqualifiedId FirstTypeName; SourceLocation CCLoc; if (Tok.is(tok::identifier)) { FirstTypeName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); CCLoc = ConsumeToken(); } else if (Tok.is(tok::annot_template_id)) { // FIXME: retrieve TemplateKWLoc from template-id annotation and // store it in the pseudo-dtor node (to be used when instantiating it). FirstTypeName.setTemplateId( (TemplateIdAnnotation *)Tok.getAnnotationValue()); ConsumeToken(); assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); CCLoc = ConsumeToken(); } else { FirstTypeName.setIdentifier(0, SourceLocation()); } // Parse the tilde. assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail"); SourceLocation TildeLoc = ConsumeToken(); if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) { DeclSpec DS(AttrFactory); ParseDecltypeSpecifier(DS); if (DS.getTypeSpecType() == TST_error) return ExprError(); return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind, TildeLoc, DS, Tok.is(tok::l_paren)); } if (!Tok.is(tok::identifier)) { Diag(Tok, diag::err_destructor_tilde_identifier); return ExprError(); } // Parse the second type. UnqualifiedId SecondTypeName; IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation NameLoc = ConsumeToken(); SecondTypeName.setIdentifier(Name, NameLoc); // If there is a '<', the second type name is a template-id. Parse // it as such. if (Tok.is(tok::less) && ParseUnqualifiedIdTemplateId(SS, SourceLocation(), Name, NameLoc, false, ObjectType, SecondTypeName, /*AssumeTemplateName=*/true)) return ExprError(); return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind, SS, FirstTypeName, CCLoc, TildeLoc, SecondTypeName, Tok.is(tok::l_paren)); } /// ParseCXXBoolLiteral - This handles the C++ Boolean literals. /// /// boolean-literal: [C++ 2.13.5] /// 'true' /// 'false' ExprResult Parser::ParseCXXBoolLiteral() { tok::TokenKind Kind = Tok.getKind(); return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind); } /// ParseThrowExpression - This handles the C++ throw expression. /// /// throw-expression: [C++ 15] /// 'throw' assignment-expression[opt] ExprResult Parser::ParseThrowExpression() { assert(Tok.is(tok::kw_throw) && "Not throw!"); SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token. // If the current token isn't the start of an assignment-expression, // then the expression is not present. This handles things like: // "C ? throw : (void)42", which is crazy but legal. switch (Tok.getKind()) { // FIXME: move this predicate somewhere common. case tok::semi: case tok::r_paren: case tok::r_square: case tok::r_brace: case tok::colon: case tok::comma: return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, 0); default: ExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) return move(Expr); return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.take()); } } /// ParseCXXThis - This handles the C++ 'this' pointer. /// /// C++ 9.3.2: In the body of a non-static member function, the keyword this is /// a non-lvalue expression whose value is the address of the object for which /// the function is called. ExprResult Parser::ParseCXXThis() { assert(Tok.is(tok::kw_this) && "Not 'this'!"); SourceLocation ThisLoc = ConsumeToken(); return Actions.ActOnCXXThis(ThisLoc); } /// ParseCXXTypeConstructExpression - 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()"). /// See [C++ 5.2.3]. /// /// postfix-expression: [C++ 5.2p1] /// simple-type-specifier '(' expression-list[opt] ')' /// [C++0x] simple-type-specifier braced-init-list /// typename-specifier '(' expression-list[opt] ')' /// [C++0x] typename-specifier braced-init-list /// ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); assert((Tok.is(tok::l_paren) || (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace))) && "Expected '(' or '{'!"); if (Tok.is(tok::l_brace)) { ExprResult Init = ParseBraceInitializer(); if (Init.isInvalid()) return Init; Expr *InitList = Init.take(); return Actions.ActOnCXXTypeConstructExpr(TypeRep, SourceLocation(), MultiExprArg(&InitList, 1), SourceLocation()); } else { GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ExprVector Exprs(Actions); CommaLocsTy CommaLocs; if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(Exprs, CommaLocs)) { SkipUntil(tok::r_paren); return ExprError(); } } // Match the ')'. T.consumeClose(); // TypeRep could be null, if it references an invalid typedef. if (!TypeRep) return ExprError(); assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(), move_arg(Exprs), T.getCloseLocation()); } } /// ParseCXXCondition - if/switch/while condition expression. /// /// condition: /// expression /// type-specifier-seq declarator '=' assignment-expression /// [C++11] type-specifier-seq declarator '=' initializer-clause /// [C++11] type-specifier-seq declarator braced-init-list /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// /// \param ExprResult if the condition was parsed as an expression, the /// parsed expression. /// /// \param DeclResult if the condition was parsed as a declaration, the /// parsed declaration. /// /// \param Loc The location of the start of the statement that requires this /// condition, e.g., the "for" in a for loop. /// /// \param ConvertToBoolean Whether the condition expression should be /// converted to a boolean value. /// /// \returns true if there was a parsing, false otherwise. bool Parser::ParseCXXCondition(ExprResult &ExprOut, Decl *&DeclOut, SourceLocation Loc, bool ConvertToBoolean) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); cutOffParsing(); return true; } if (!isCXXConditionDeclaration()) { // Parse the expression. ExprOut = ParseExpression(); // expression DeclOut = 0; if (ExprOut.isInvalid()) return true; // If required, convert to a boolean value. if (ConvertToBoolean) ExprOut = Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprOut.get()); return ExprOut.isInvalid(); } // type-specifier-seq DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // declarator Declarator DeclaratorInfo(DS, Declarator::ConditionContext); ParseDeclarator(DeclaratorInfo); // simple-asm-expr[opt] if (Tok.is(tok::kw_asm)) { SourceLocation Loc; ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi); return true; } DeclaratorInfo.setAsmLabel(AsmLabel.release()); DeclaratorInfo.SetRangeEnd(Loc); } // If attributes are present, parse them. MaybeParseGNUAttributes(DeclaratorInfo); // Type-check the declaration itself. DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(), DeclaratorInfo); DeclOut = Dcl.get(); ExprOut = ExprError(); // '=' assignment-expression // If a '==' or '+=' is found, suggest a fixit to '='. bool CopyInitialization = isTokenEqualOrEqualTypo(); if (CopyInitialization) ConsumeToken(); ExprResult InitExpr = ExprError(); if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_generalized_initializer_lists); InitExpr = ParseBraceInitializer(); } else if (CopyInitialization) { InitExpr = ParseAssignmentExpression(); } else if (Tok.is(tok::l_paren)) { // This was probably an attempt to initialize the variable. SourceLocation LParen = ConsumeParen(), RParen = LParen; if (SkipUntil(tok::r_paren, true, /*DontConsume=*/true)) RParen = ConsumeParen(); Diag(DeclOut ? DeclOut->getLocation() : LParen, diag::err_expected_init_in_condition_lparen) << SourceRange(LParen, RParen); } else { Diag(DeclOut ? DeclOut->getLocation() : Tok.getLocation(), diag::err_expected_init_in_condition); } if (!InitExpr.isInvalid()) Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization, DS.getTypeSpecType() == DeclSpec::TST_auto); // FIXME: Build a reference to this declaration? Convert it to bool? // (This is currently handled by Sema). Actions.FinalizeDeclaration(DeclOut); return false; } /// \brief Determine whether the current token starts a C++ /// simple-type-specifier. bool Parser::isCXXSimpleTypeSpecifier() const { switch (Tok.getKind()) { case tok::annot_typename: 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_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_bool: case tok::kw_decltype: case tok::kw_typeof: case tok::kw___underlying_type: return true; default: break; } return false; } /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. /// This should only be called when the current token is known to be part of /// simple-type-specifier. /// /// simple-type-specifier: /// '::'[opt] nested-name-specifier[opt] type-name /// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO] /// char /// wchar_t /// bool /// short /// int /// long /// signed /// unsigned /// float /// double /// void /// [GNU] typeof-specifier /// [C++0x] auto [TODO] /// /// type-name: /// class-name /// enum-name /// typedef-name /// void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { DS.SetRangeStart(Tok.getLocation()); const char *PrevSpec; unsigned DiagID; SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { case tok::identifier: // foo::bar case tok::coloncolon: // ::foo::bar llvm_unreachable("Annotation token should already be formed!"); default: llvm_unreachable("Not a simple-type-specifier token!"); // type-name case tok::annot_typename: { if (getTypeAnnotation(Tok)) DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, getTypeAnnotation(Tok)); else DS.SetTypeSpecError(); DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // Objective-C supports syntax of the form 'id' where 'id' // is a specific typedef and 'itf' where 'itf' is an // Objective-C interface. If we don't have Objective-C or a '<', this is // just a normal reference to a typedef name. if (Tok.is(tok::less) && getLangOpts().ObjC1) ParseObjCProtocolQualifiers(DS); DS.Finish(Diags, PP); return; } // builtin types case tok::kw_short: DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID); break; case tok::kw_long: DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID); break; case tok::kw___int64: DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID); break; case tok::kw_signed: DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); break; case tok::kw_unsigned: DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, DiagID); break; case tok::kw_void: DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID); break; case tok::kw_char: DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID); break; case tok::kw_int: DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; case tok::kw___int128: DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID); break; case tok::kw_half: DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID); break; case tok::kw_float: DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); break; case tok::kw_double: DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID); break; case tok::kw_wchar_t: DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID); break; case tok::kw_char16_t: DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID); break; case tok::kw_char32_t: DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID); break; case tok::kw_bool: DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); break; case tok::annot_decltype: case tok::kw_decltype: DS.SetRangeEnd(ParseDecltypeSpecifier(DS)); return DS.Finish(Diags, PP); // GNU typeof support. case tok::kw_typeof: ParseTypeofSpecifier(DS); DS.Finish(Diags, PP); return; } if (Tok.is(tok::annot_typename)) DS.SetRangeEnd(Tok.getAnnotationEndLoc()); else DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); DS.Finish(Diags, PP); } /// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++ /// [dcl.name]), which is a non-empty sequence of type-specifiers, /// e.g., "const short int". Note that the DeclSpec is *not* finished /// by parsing the type-specifier-seq, because these sequences are /// typically followed by some form of declarator. Returns true and /// emits diagnostics if this is not a type-specifier-seq, false /// otherwise. /// /// type-specifier-seq: [C++ 8.1] /// type-specifier type-specifier-seq[opt] /// bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { ParseSpecifierQualifierList(DS, AS_none, DSC_type_specifier); DS.Finish(Diags, PP); return false; } /// \brief Finish parsing a C++ unqualified-id that is a template-id of /// some form. /// /// This routine is invoked when a '<' is encountered after an identifier or /// operator-function-id is parsed by \c ParseUnqualifiedId() to determine /// whether the unqualified-id is actually a template-id. This routine will /// then parse the template arguments and form the appropriate template-id to /// return to the caller. /// /// \param SS the nested-name-specifier that precedes this template-id, if /// we're actually parsing a qualified-id. /// /// \param Name for constructor and destructor names, this is the actual /// identifier that may be a template-name. /// /// \param NameLoc the location of the class-name in a constructor or /// destructor. /// /// \param EnteringContext whether we're entering the scope of the /// nested-name-specifier. /// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param Id as input, describes the template-name or operator-function-id /// that precedes the '<'. If template arguments were parsed successfully, /// will be updated with the template-id. /// /// \param AssumeTemplateId When true, this routine will assume that the name /// refers to a template without performing name lookup to verify. /// /// \returns true if a parse error occurred, false otherwise. bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext, ParsedType ObjectType, UnqualifiedId &Id, bool AssumeTemplateId) { assert((AssumeTemplateId || Tok.is(tok::less)) && "Expected '<' to finish parsing a template-id"); TemplateTy Template; TemplateNameKind TNK = TNK_Non_template; switch (Id.getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: if (AssumeTemplateId) { TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, Template); if (TNK == TNK_Non_template) return true; } else { bool MemberOfUnknownSpecialization; TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), Id, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && MemberOfUnknownSpecialization && ObjectType && IsTemplateArgumentList()) { // We have something like t->getAs(), where getAs is a // member of an unknown specialization. However, this will only // parse correctly as a template, so suggest the keyword 'template' // before 'getAs' and treat this as a dependent template name. std::string Name; if (Id.getKind() == UnqualifiedId::IK_Identifier) Name = Id.Identifier->getName(); else { Name = "operator "; if (Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) Name += getOperatorSpelling(Id.OperatorFunctionId.Operator); else Name += Id.Identifier->getName(); } Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword) << Name << FixItHint::CreateInsertion(Id.StartLocation, "template "); TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, Template); if (TNK == TNK_Non_template) return true; } } break; case UnqualifiedId::IK_ConstructorName: { UnqualifiedId TemplateName; bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); break; } case UnqualifiedId::IK_DestructorName: { UnqualifiedId TemplateName; bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, EnteringContext, Template); if (TNK == TNK_Non_template) return true; } else { TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && !Id.DestructorName.get()) { Diag(NameLoc, diag::err_destructor_template_id) << Name << SS.getRange(); return true; } } break; } default: return false; } if (TNK == TNK_Non_template) return false; // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; if (Tok.is(tok::less) && ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) return true; if (Id.getKind() == UnqualifiedId::IK_Identifier || Id.getKind() == UnqualifiedId::IK_OperatorFunctionId || Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) { // Form a parsed representation of the template-id to be stored in the // UnqualifiedId. TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds); if (Id.getKind() == UnqualifiedId::IK_Identifier) { TemplateId->Name = Id.Identifier; TemplateId->Operator = OO_None; TemplateId->TemplateNameLoc = Id.StartLocation; } else { TemplateId->Name = 0; TemplateId->Operator = Id.OperatorFunctionId.Operator; TemplateId->TemplateNameLoc = Id.StartLocation; } TemplateId->SS = SS; TemplateId->TemplateKWLoc = TemplateKWLoc; TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; TemplateId->RAngleLoc = RAngleLoc; ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) Args[Arg] = TemplateArgs[Arg]; Id.setTemplateId(TemplateId); return false; } // Bundle the template arguments together. ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), TemplateArgs.size()); // Constructor and destructor names. TypeResult Type = Actions.ActOnTemplateIdType(SS, TemplateKWLoc, Template, NameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc, /*IsCtorOrDtorName=*/true); if (Type.isInvalid()) return true; if (Id.getKind() == UnqualifiedId::IK_ConstructorName) Id.setConstructorName(Type.get(), NameLoc, RAngleLoc); else Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc); return false; } /// \brief Parse an operator-function-id or conversion-function-id as part /// of a C++ unqualified-id. /// /// This routine is responsible only for parsing the operator-function-id or /// conversion-function-id; it does not handle template arguments in any way. /// /// \code /// operator-function-id: [C++ 13.5] /// 'operator' operator /// /// operator: one of /// new delete new[] delete[] /// + - * / % ^ & | ~ /// ! = < > += -= *= /= %= /// ^= &= |= << >> >>= <<= == != /// <= >= && || ++ -- , ->* -> /// () [] /// /// conversion-function-id: [C++ 12.3.2] /// operator conversion-type-id /// /// conversion-type-id: /// type-specifier-seq conversion-declarator[opt] /// /// conversion-declarator: /// ptr-operator conversion-declarator[opt] /// \endcode /// /// \param The nested-name-specifier that preceded this unqualified-id. If /// non-empty, then we are parsing the unqualified-id of a qualified-id. /// /// \param EnteringContext whether we are entering the scope of the /// nested-name-specifier. /// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param Result on a successful parse, contains the parsed unqualified-id. /// /// \returns true if parsing fails, false otherwise. bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, ParsedType ObjectType, UnqualifiedId &Result) { assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); // Consume the 'operator' keyword. SourceLocation KeywordLoc = ConsumeToken(); // Determine what kind of operator name we have. unsigned SymbolIdx = 0; SourceLocation SymbolLocations[3]; OverloadedOperatorKind Op = OO_None; switch (Tok.getKind()) { case tok::kw_new: case tok::kw_delete: { bool isNew = Tok.getKind() == tok::kw_new; // Consume the 'new' or 'delete'. SymbolLocations[SymbolIdx++] = ConsumeToken(); // Check for array new/delete. if (Tok.is(tok::l_square) && (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))) { // Consume the '[' and ']'. BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return true; SymbolLocations[SymbolIdx++] = T.getOpenLocation(); SymbolLocations[SymbolIdx++] = T.getCloseLocation(); Op = isNew? OO_Array_New : OO_Array_Delete; } else { Op = isNew? OO_New : OO_Delete; } break; } #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ case tok::Token: \ SymbolLocations[SymbolIdx++] = ConsumeToken(); \ Op = OO_##Name; \ break; #define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) #include "clang/Basic/OperatorKinds.def" case tok::l_paren: { // Consume the '(' and ')'. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return true; SymbolLocations[SymbolIdx++] = T.getOpenLocation(); SymbolLocations[SymbolIdx++] = T.getCloseLocation(); Op = OO_Call; break; } case tok::l_square: { // Consume the '[' and ']'. BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return true; SymbolLocations[SymbolIdx++] = T.getOpenLocation(); SymbolLocations[SymbolIdx++] = T.getCloseLocation(); Op = OO_Subscript; break; } case tok::code_completion: { // Code completion for the operator name. Actions.CodeCompleteOperatorName(getCurScope()); cutOffParsing(); // Don't try to parse any further. return true; } default: break; } if (Op != OO_None) { // We have parsed an operator-function-id. Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations); return false; } // Parse a literal-operator-id. // // literal-operator-id: [C++0x 13.5.8] // operator "" identifier if (getLangOpts().CPlusPlus0x && isTokenStringLiteral()) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator); SourceLocation DiagLoc; unsigned DiagId = 0; // We're past translation phase 6, so perform string literal concatenation // before checking for "". llvm::SmallVector Toks; llvm::SmallVector TokLocs; while (isTokenStringLiteral()) { if (!Tok.is(tok::string_literal) && !DiagId) { DiagLoc = Tok.getLocation(); DiagId = diag::err_literal_operator_string_prefix; } Toks.push_back(Tok); TokLocs.push_back(ConsumeStringToken()); } StringLiteralParser Literal(Toks.data(), Toks.size(), PP); if (Literal.hadError) return true; // Grab the literal operator's suffix, which will be either the next token // or a ud-suffix from the string literal. IdentifierInfo *II = 0; SourceLocation SuffixLoc; if (!Literal.getUDSuffix().empty()) { II = &PP.getIdentifierTable().get(Literal.getUDSuffix()); SuffixLoc = Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()], Literal.getUDSuffixOffset(), PP.getSourceManager(), getLangOpts()); // This form is not permitted by the standard (yet). DiagLoc = SuffixLoc; DiagId = diag::err_literal_operator_missing_space; } else if (Tok.is(tok::identifier)) { II = Tok.getIdentifierInfo(); SuffixLoc = ConsumeToken(); TokLocs.push_back(SuffixLoc); } else { Diag(Tok.getLocation(), diag::err_expected_ident); return true; } // The string literal must be empty. if (!Literal.GetString().empty() || Literal.Pascal) { DiagLoc = TokLocs.front(); DiagId = diag::err_literal_operator_string_not_empty; } if (DiagId) { // This isn't a valid literal-operator-id, but we think we know // what the user meant. Tell them what they should have written. llvm::SmallString<32> Str; Str += "\"\" "; Str += II->getName(); Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement( SourceRange(TokLocs.front(), TokLocs.back()), Str); } Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc); return false; } // Parse a conversion-function-id. // // conversion-function-id: [C++ 12.3.2] // operator conversion-type-id // // conversion-type-id: // type-specifier-seq conversion-declarator[opt] // // conversion-declarator: // ptr-operator conversion-declarator[opt] // Parse the type-specifier-seq. DeclSpec DS(AttrFactory); if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType? return true; // Parse the conversion-declarator, which is merely a sequence of // ptr-operators. Declarator D(DS, Declarator::TypeNameContext); ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); // Finish up the type. TypeResult Ty = Actions.ActOnTypeName(getCurScope(), D); if (Ty.isInvalid()) return true; // Note that this is a conversion-function-id. Result.setConversionFunctionId(KeywordLoc, Ty.get(), D.getSourceRange().getEnd()); return false; } /// \brief Parse a C++ unqualified-id (or a C identifier), which describes the /// name of an entity. /// /// \code /// unqualified-id: [C++ expr.prim.general] /// identifier /// operator-function-id /// conversion-function-id /// [C++0x] literal-operator-id [TODO] /// ~ class-name /// template-id /// /// \endcode /// /// \param The nested-name-specifier that preceded this unqualified-id. If /// non-empty, then we are parsing the unqualified-id of a qualified-id. /// /// \param EnteringContext whether we are entering the scope of the /// nested-name-specifier. /// /// \param AllowDestructorName whether we allow parsing of a destructor name. /// /// \param AllowConstructorName whether we allow parsing a constructor name. /// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param Result on a successful parse, contains the parsed unqualified-id. /// /// \returns true if parsing fails, false otherwise. bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, ParsedType ObjectType, SourceLocation& TemplateKWLoc, UnqualifiedId &Result) { // Handle 'A::template B'. This is for template-ids which have not // already been annotated by ParseOptionalCXXScopeSpecifier(). bool TemplateSpecified = false; if (getLangOpts().CPlusPlus && Tok.is(tok::kw_template) && (ObjectType || SS.isSet())) { TemplateSpecified = true; TemplateKWLoc = ConsumeToken(); } // unqualified-id: // identifier // template-id (when it hasn't already been annotated) if (Tok.is(tok::identifier)) { // Consume the identifier. IdentifierInfo *Id = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); if (!getLangOpts().CPlusPlus) { // If we're not in C++, only identifiers matter. Record the // identifier and return. Result.setIdentifier(Id, IdLoc); return false; } if (AllowConstructorName && Actions.isCurrentClassName(*Id, getCurScope(), &SS)) { // We have parsed a constructor name. ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, false, false, ParsedType(), /*IsCtorOrDtorName=*/true, /*NonTrivialTypeSourceInfo=*/true); Result.setConstructorName(Ty, IdLoc, IdLoc); } else { // We have parsed an identifier. Result.setIdentifier(Id, IdLoc); } // If the next token is a '<', we may have a template. if (TemplateSpecified || Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, Id, IdLoc, EnteringContext, ObjectType, Result, TemplateSpecified); return false; } // unqualified-id: // template-id (already parsed and annotated) if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); // If the template-name names the current class, then this is a constructor if (AllowConstructorName && TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) { if (SS.isSet()) { // C++ [class.qual]p2 specifies that a qualified template-name // is taken as the constructor name where a constructor can be // declared. Thus, the template arguments are extraneous, so // complain about them and remove them entirely. Diag(TemplateId->TemplateNameLoc, diag::err_out_of_line_constructor_template_id) << TemplateId->Name << FixItHint::CreateRemoval( SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); ParsedType Ty = Actions.getTypeName(*TemplateId->Name, TemplateId->TemplateNameLoc, getCurScope(), &SS, false, false, ParsedType(), /*IsCtorOrDtorName=*/true, /*NontrivialTypeSourceInfo=*/true); Result.setConstructorName(Ty, TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); ConsumeToken(); return false; } Result.setConstructorTemplateId(TemplateId); ConsumeToken(); return false; } // We have already parsed a template-id; consume the annotation token as // our unqualified-id. Result.setTemplateId(TemplateId); TemplateKWLoc = TemplateId->TemplateKWLoc; ConsumeToken(); return false; } // unqualified-id: // operator-function-id // conversion-function-id if (Tok.is(tok::kw_operator)) { if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result)) return true; // If we have an operator-function-id or a literal-operator-id and the next // token is a '<', we may have a // // template-id: // operator-function-id < template-argument-list[opt] > if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId || Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) && (TemplateSpecified || Tok.is(tok::less))) return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, 0, SourceLocation(), EnteringContext, ObjectType, Result, TemplateSpecified); return false; } if (getLangOpts().CPlusPlus && (AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) { // C++ [expr.unary.op]p10: // There is an ambiguity in the unary-expression ~X(), where X is a // class-name. The ambiguity is resolved in favor of treating ~ as a // unary complement rather than treating ~X as referring to a destructor. // Parse the '~'. SourceLocation TildeLoc = ConsumeToken(); if (SS.isEmpty() && Tok.is(tok::kw_decltype)) { DeclSpec DS(AttrFactory); SourceLocation EndLoc = ParseDecltypeSpecifier(DS); if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) { Result.setDestructorName(TildeLoc, Type, EndLoc); return false; } return true; } // Parse the class-name. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_destructor_tilde_identifier); return true; } // Parse the class-name (or template-name in a simple-template-id). IdentifierInfo *ClassName = Tok.getIdentifierInfo(); SourceLocation ClassNameLoc = ConsumeToken(); if (TemplateSpecified || Tok.is(tok::less)) { Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc); return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, ClassName, ClassNameLoc, EnteringContext, ObjectType, Result, TemplateSpecified); } // Note that this is a destructor name. ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName, ClassNameLoc, getCurScope(), SS, ObjectType, EnteringContext); if (!Ty) return true; Result.setDestructorName(TildeLoc, Ty, ClassNameLoc); return false; } Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; return true; } /// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate /// memory in a typesafe manner and call constructors. /// /// This method is called to parse the new expression after the optional :: has /// been already parsed. If the :: was present, "UseGlobal" is true and "Start" /// is its location. Otherwise, "Start" is the location of the 'new' token. /// /// new-expression: /// '::'[opt] 'new' new-placement[opt] new-type-id /// new-initializer[opt] /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// new-placement: /// '(' expression-list ')' /// /// new-type-id: /// type-specifier-seq new-declarator[opt] /// [GNU] attributes type-specifier-seq new-declarator[opt] /// /// new-declarator: /// ptr-operator new-declarator[opt] /// direct-new-declarator /// /// new-initializer: /// '(' expression-list[opt] ')' /// [C++0x] braced-init-list /// ExprResult Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { assert(Tok.is(tok::kw_new) && "expected 'new' token"); ConsumeToken(); // Consume 'new' // A '(' now can be a new-placement or the '(' wrapping the type-id in the // second form of new-expression. It can't be a new-type-id. ExprVector PlacementArgs(Actions); SourceLocation PlacementLParen, PlacementRParen; SourceRange TypeIdParens; DeclSpec DS(AttrFactory); Declarator DeclaratorInfo(DS, Declarator::CXXNewContext); if (Tok.is(tok::l_paren)) { // If it turns out to be a placement, we change the type location. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); PlacementLParen = T.getOpenLocation(); if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); } T.consumeClose(); PlacementRParen = T.getCloseLocation(); if (PlacementRParen.isInvalid()) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); } if (PlacementArgs.empty()) { // Reset the placement locations. There was no placement. TypeIdParens = T.getRange(); PlacementLParen = PlacementRParen = SourceLocation(); } else { // We still need the type. if (Tok.is(tok::l_paren)) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); MaybeParseGNUAttributes(DeclaratorInfo); ParseSpecifierQualifierList(DS); DeclaratorInfo.SetSourceRange(DS.getSourceRange()); ParseDeclarator(DeclaratorInfo); T.consumeClose(); TypeIdParens = T.getRange(); } else { MaybeParseGNUAttributes(DeclaratorInfo); if (ParseCXXTypeSpecifierSeq(DS)) DeclaratorInfo.setInvalidType(true); else { DeclaratorInfo.SetSourceRange(DS.getSourceRange()); ParseDeclaratorInternal(DeclaratorInfo, &Parser::ParseDirectNewDeclarator); } } } } else { // A new-type-id is a simplified type-id, where essentially the // direct-declarator is replaced by a direct-new-declarator. MaybeParseGNUAttributes(DeclaratorInfo); if (ParseCXXTypeSpecifierSeq(DS)) DeclaratorInfo.setInvalidType(true); else { DeclaratorInfo.SetSourceRange(DS.getSourceRange()); ParseDeclaratorInternal(DeclaratorInfo, &Parser::ParseDirectNewDeclarator); } } if (DeclaratorInfo.isInvalidType()) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); } ExprResult Initializer; if (Tok.is(tok::l_paren)) { SourceLocation ConstructorLParen, ConstructorRParen; ExprVector ConstructorArgs(Actions); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ConstructorLParen = T.getOpenLocation(); if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; if (ParseExpressionList(ConstructorArgs, CommaLocs)) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); } } T.consumeClose(); ConstructorRParen = T.getCloseLocation(); if (ConstructorRParen.isInvalid()) { SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return ExprError(); } Initializer = Actions.ActOnParenListExpr(ConstructorLParen, ConstructorRParen, move_arg(ConstructorArgs)); } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus0x) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_generalized_initializer_lists); Initializer = ParseBraceInitializer(); } if (Initializer.isInvalid()) return Initializer; return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, move_arg(PlacementArgs), PlacementRParen, TypeIdParens, DeclaratorInfo, Initializer.take()); } /// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be /// passed to ParseDeclaratorInternal. /// /// direct-new-declarator: /// '[' expression ']' /// direct-new-declarator '[' constant-expression ']' /// void Parser::ParseDirectNewDeclarator(Declarator &D) { // Parse the array dimensions. bool first = true; while (Tok.is(tok::l_square)) { // An array-size expression can't start with a lambda. if (CheckProhibitedCXX11Attribute()) continue; BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); ExprResult Size(first ? ParseExpression() : ParseConstantExpression()); if (Size.isInvalid()) { // Recover SkipUntil(tok::r_square); return; } first = false; T.consumeClose(); // Attributes here appertain to the array type. C++11 [expr.new]p5. ParsedAttributes Attrs(AttrFactory); MaybeParseCXX0XAttributes(Attrs); D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, Size.release(), T.getOpenLocation(), T.getCloseLocation()), Attrs, T.getCloseLocation()); if (T.getCloseLocation().isInvalid()) return; } } /// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id. /// This ambiguity appears in the syntax of the C++ new operator. /// /// new-expression: /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// new-placement: /// '(' expression-list ')' /// bool Parser::ParseExpressionListOrTypeId( SmallVectorImpl &PlacementArgs, Declarator &D) { // The '(' was already consumed. if (isTypeIdInParens()) { ParseSpecifierQualifierList(D.getMutableDeclSpec()); D.SetSourceRange(D.getDeclSpec().getSourceRange()); ParseDeclarator(D); return D.isInvalidType(); } // It's not a type, it has to be an expression list. // Discard the comma locations - ActOnCXXNew has enough parameters. CommaLocsTy CommaLocs; return ParseExpressionList(PlacementArgs, CommaLocs); } /// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used /// to free memory allocated by new. /// /// This method is called to parse the 'delete' expression after the optional /// '::' has been already parsed. If the '::' was present, "UseGlobal" is true /// and "Start" is its location. Otherwise, "Start" is the location of the /// 'delete' token. /// /// delete-expression: /// '::'[opt] 'delete' cast-expression /// '::'[opt] 'delete' '[' ']' cast-expression ExprResult Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword"); ConsumeToken(); // Consume 'delete' // Array delete? bool ArrayDelete = false; if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) { // FIXME: This could be the start of a lambda-expression. We should // disambiguate this, but that will require arbitrary lookahead if // the next token is '(': // delete [](int*){ /* ... */ ArrayDelete = true; BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return ExprError(); } ExprResult Operand(ParseCastExpression(false)); if (Operand.isInvalid()) return move(Operand); return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.take()); } static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { default: llvm_unreachable("Not a known unary type trait."); case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign; case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor; case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy; case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign; case tok::kw___has_trivial_constructor: return UTT_HasTrivialDefaultConstructor; case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy; case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor; case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor; case tok::kw___is_abstract: return UTT_IsAbstract; case tok::kw___is_arithmetic: return UTT_IsArithmetic; case tok::kw___is_array: return UTT_IsArray; case tok::kw___is_class: return UTT_IsClass; case tok::kw___is_complete_type: return UTT_IsCompleteType; case tok::kw___is_compound: return UTT_IsCompound; case tok::kw___is_const: return UTT_IsConst; case tok::kw___is_empty: return UTT_IsEmpty; case tok::kw___is_enum: return UTT_IsEnum; case tok::kw___is_final: return UTT_IsFinal; case tok::kw___is_floating_point: return UTT_IsFloatingPoint; case tok::kw___is_function: return UTT_IsFunction; case tok::kw___is_fundamental: return UTT_IsFundamental; case tok::kw___is_integral: return UTT_IsIntegral; case tok::kw___is_lvalue_reference: return UTT_IsLvalueReference; case tok::kw___is_member_function_pointer: return UTT_IsMemberFunctionPointer; case tok::kw___is_member_object_pointer: return UTT_IsMemberObjectPointer; case tok::kw___is_member_pointer: return UTT_IsMemberPointer; case tok::kw___is_object: return UTT_IsObject; case tok::kw___is_literal: return UTT_IsLiteral; case tok::kw___is_literal_type: return UTT_IsLiteral; case tok::kw___is_pod: return UTT_IsPOD; case tok::kw___is_pointer: return UTT_IsPointer; case tok::kw___is_polymorphic: return UTT_IsPolymorphic; case tok::kw___is_reference: return UTT_IsReference; case tok::kw___is_rvalue_reference: return UTT_IsRvalueReference; case tok::kw___is_scalar: return UTT_IsScalar; case tok::kw___is_signed: return UTT_IsSigned; case tok::kw___is_standard_layout: return UTT_IsStandardLayout; case tok::kw___is_trivial: return UTT_IsTrivial; case tok::kw___is_trivially_copyable: return UTT_IsTriviallyCopyable; case tok::kw___is_union: return UTT_IsUnion; case tok::kw___is_unsigned: return UTT_IsUnsigned; case tok::kw___is_void: return UTT_IsVoid; case tok::kw___is_volatile: return UTT_IsVolatile; } } static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { default: llvm_unreachable("Not a known binary type trait"); case tok::kw___is_base_of: return BTT_IsBaseOf; case tok::kw___is_convertible: return BTT_IsConvertible; case tok::kw___is_same: return BTT_IsSame; case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible; case tok::kw___is_convertible_to: return BTT_IsConvertibleTo; case tok::kw___is_trivially_assignable: return BTT_IsTriviallyAssignable; } } static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) { switch (kind) { default: llvm_unreachable("Not a known type trait"); case tok::kw___is_trivially_constructible: return TT_IsTriviallyConstructible; } } static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { default: llvm_unreachable("Not a known binary type trait"); case tok::kw___array_rank: return ATT_ArrayRank; case tok::kw___array_extent: return ATT_ArrayExtent; } } static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) { switch(kind) { default: llvm_unreachable("Not a known unary expression trait."); case tok::kw___is_lvalue_expr: return ET_IsLValueExpr; case tok::kw___is_rvalue_expr: return ET_IsRValueExpr; } } /// ParseUnaryTypeTrait - Parse the built-in unary type-trait /// pseudo-functions that allow implementation of the TR1/C++0x type traits /// templates. /// /// primary-expression: /// [GNU] unary-type-trait '(' type-id ')' /// ExprResult Parser::ParseUnaryTypeTrait() { UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); // FIXME: Error reporting absolutely sucks! If the this fails to parse a type // there will be cryptic errors about mismatched parentheses and missing // specifiers. TypeResult Ty = ParseTypeName(); T.consumeClose(); if (Ty.isInvalid()) return ExprError(); return Actions.ActOnUnaryTypeTrait(UTT, Loc, Ty.get(), T.getCloseLocation()); } /// ParseBinaryTypeTrait - Parse the built-in binary type-trait /// pseudo-functions that allow implementation of the TR1/C++0x type traits /// templates. /// /// primary-expression: /// [GNU] binary-type-trait '(' type-id ',' type-id ')' /// ExprResult Parser::ParseBinaryTypeTrait() { BinaryTypeTrait BTT = BinaryTypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); TypeResult LhsTy = ParseTypeName(); if (LhsTy.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); } if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { SkipUntil(tok::r_paren); return ExprError(); } TypeResult RhsTy = ParseTypeName(); if (RhsTy.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); } T.consumeClose(); return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), T.getCloseLocation()); } /// \brief Parse the built-in type-trait pseudo-functions that allow /// implementation of the TR1/C++11 type traits templates. /// /// primary-expression: /// type-trait '(' type-id-seq ')' /// /// type-id-seq: /// type-id ...[opt] type-id-seq[opt] /// ExprResult Parser::ParseTypeTrait() { TypeTrait Kind = TypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker Parens(*this, tok::l_paren); if (Parens.expectAndConsume(diag::err_expected_lparen)) return ExprError(); llvm::SmallVector Args; do { // Parse the next type. TypeResult Ty = ParseTypeName(); if (Ty.isInvalid()) { Parens.skipToEnd(); return ExprError(); } // Parse the ellipsis, if present. if (Tok.is(tok::ellipsis)) { Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken()); if (Ty.isInvalid()) { Parens.skipToEnd(); return ExprError(); } } // Add this type to the list of arguments. Args.push_back(Ty.get()); if (Tok.is(tok::comma)) { ConsumeToken(); continue; } break; } while (true); if (Parens.consumeClose()) return ExprError(); return Actions.ActOnTypeTrait(Kind, Loc, Args, Parens.getCloseLocation()); } /// ParseArrayTypeTrait - Parse the built-in array type-trait /// pseudo-functions. /// /// primary-expression: /// [Embarcadero] '__array_rank' '(' type-id ')' /// [Embarcadero] '__array_extent' '(' type-id ',' expression ')' /// ExprResult Parser::ParseArrayTypeTrait() { ArrayTypeTrait ATT = ArrayTypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); TypeResult Ty = ParseTypeName(); if (Ty.isInvalid()) { SkipUntil(tok::comma); SkipUntil(tok::r_paren); return ExprError(); } switch (ATT) { case ATT_ArrayRank: { T.consumeClose(); return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL, T.getCloseLocation()); } case ATT_ArrayExtent: { if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { SkipUntil(tok::r_paren); return ExprError(); } ExprResult DimExpr = ParseExpression(); T.consumeClose(); return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), T.getCloseLocation()); } } llvm_unreachable("Invalid ArrayTypeTrait!"); } /// ParseExpressionTrait - Parse built-in expression-trait /// pseudo-functions like __is_lvalue_expr( xxx ). /// /// primary-expression: /// [Embarcadero] expression-trait '(' expression ')' /// ExprResult Parser::ParseExpressionTrait() { ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen)) return ExprError(); ExprResult Expr = ParseExpression(); T.consumeClose(); return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), T.getCloseLocation()); } /// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a /// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate /// based on the context past the parens. ExprResult Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ParsedType &CastTy, BalancedDelimiterTracker &Tracker) { assert(getLangOpts().CPlusPlus && "Should only be called for C++!"); assert(ExprType == CastExpr && "Compound literals are not ambiguous!"); assert(isTypeIdInParens() && "Not a type-id!"); ExprResult Result(true); CastTy = ParsedType(); // We need to disambiguate a very ugly part of the C++ syntax: // // (T())x; - type-id // (T())*x; - type-id // (T())/x; - expression // (T()); - expression // // The bad news is that we cannot use the specialized tentative parser, since // it can only verify that the thing inside the parens can be parsed as // type-id, it is not useful for determining the context past the parens. // // The good news is that the parser can disambiguate this part without // making any unnecessary Action calls. // // It uses a scheme similar to parsing inline methods. The parenthesized // tokens are cached, the context that follows is determined (possibly by // parsing a cast-expression), and then we re-introduce the cached tokens // into the token stream and parse them appropriately. ParenParseOption ParseAs; CachedTokens Toks; // Store the tokens of the parentheses. We will parse them after we determine // the context that follows them. if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) { // We didn't find the ')' we expected. Tracker.consumeClose(); return ExprError(); } if (Tok.is(tok::l_brace)) { ParseAs = CompoundLiteral; } else { bool NotCastExpr; // FIXME: Special-case ++ and --: "(S())++;" is not a cast-expression if (Tok.is(tok::l_paren) && NextToken().is(tok::r_paren)) { NotCastExpr = true; } else { // Try parsing the cast-expression that may follow. // If it is not a cast-expression, NotCastExpr will be true and no token // will be consumed. Result = ParseCastExpression(false/*isUnaryExpression*/, false/*isAddressofOperand*/, NotCastExpr, // type-id has priority. IsTypeCast); } // If we parsed a cast-expression, it's really a type-id, otherwise it's // an expression. ParseAs = NotCastExpr ? SimpleExpr : CastExpr; } // The current token should go after the cached tokens. Toks.push_back(Tok); // Re-enter the stored parenthesized tokens into the token stream, so we may // parse them now. PP.EnterTokenStream(Toks.data(), Toks.size(), true/*DisableMacroExpansion*/, false/*OwnsTokens*/); // Drop the current token and bring the first cached one. It's the same token // as when we entered this function. ConsumeAnyToken(); if (ParseAs >= CompoundLiteral) { // Parse the type declarator. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParseDeclarator(DeclaratorInfo); // Match the ')'. Tracker.consumeClose(); if (ParseAs == CompoundLiteral) { ExprType = CompoundLiteral; TypeResult Ty = ParseTypeName(); return ParseCompoundLiteralExpression(Ty.get(), Tracker.getOpenLocation(), Tracker.getCloseLocation()); } // We parsed '(' type-id ')' and the thing after it wasn't a '{'. assert(ParseAs == CastExpr); if (DeclaratorInfo.isInvalidType()) return ExprError(); // Result is what ParseCastExpression returned earlier. if (!Result.isInvalid()) Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(), DeclaratorInfo, CastTy, Tracker.getCloseLocation(), Result.take()); return move(Result); } // Not a compound literal, and not followed by a cast-expression. assert(ParseAs == SimpleExpr); ExprType = SimpleExpr; Result = ParseExpression(); if (!Result.isInvalid() && Tok.is(tok::r_paren)) Result = Actions.ActOnParenExpr(Tracker.getOpenLocation(), Tok.getLocation(), Result.take()); // Match the ')'. if (Result.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); } Tracker.consumeClose(); return move(Result); } Index: vendor/clang/dist/lib/Sema/DeclSpec.cpp =================================================================== --- vendor/clang/dist/lib/Sema/DeclSpec.cpp (revision 235808) +++ vendor/clang/dist/lib/Sema/DeclSpec.cpp (revision 235809) @@ -1,991 +1,986 @@ //===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===// // // 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 declaration specifiers. // //===----------------------------------------------------------------------===// #include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency! #include "clang/Sema/DeclSpec.h" #include "clang/Sema/LocInfoType.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/Sema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TypeLoc.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" #include using namespace clang; static DiagnosticBuilder Diag(DiagnosticsEngine &D, SourceLocation Loc, unsigned DiagID) { return D.Report(Loc, DiagID); } void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { assert(TemplateId && "NULL template-id annotation?"); Kind = IK_TemplateId; this->TemplateId = TemplateId; StartLocation = TemplateId->TemplateNameLoc; EndLocation = TemplateId->RAngleLoc; } void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { assert(TemplateId && "NULL template-id annotation?"); Kind = IK_ConstructorTemplateId; this->TemplateId = TemplateId; StartLocation = TemplateId->TemplateNameLoc; EndLocation = TemplateId->RAngleLoc; } void CXXScopeSpec::Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, SourceLocation ColonColonLoc) { Builder.Extend(Context, TemplateKWLoc, TL, ColonColonLoc); if (Range.getBegin().isInvalid()) Range.setBegin(TL.getBeginLoc()); Range.setEnd(ColonColonLoc); assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::Extend(ASTContext &Context, IdentifierInfo *Identifier, SourceLocation IdentifierLoc, SourceLocation ColonColonLoc) { Builder.Extend(Context, Identifier, IdentifierLoc, ColonColonLoc); if (Range.getBegin().isInvalid()) Range.setBegin(IdentifierLoc); Range.setEnd(ColonColonLoc); assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::Extend(ASTContext &Context, NamespaceDecl *Namespace, SourceLocation NamespaceLoc, SourceLocation ColonColonLoc) { Builder.Extend(Context, Namespace, NamespaceLoc, ColonColonLoc); if (Range.getBegin().isInvalid()) Range.setBegin(NamespaceLoc); Range.setEnd(ColonColonLoc); assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::Extend(ASTContext &Context, NamespaceAliasDecl *Alias, SourceLocation AliasLoc, SourceLocation ColonColonLoc) { Builder.Extend(Context, Alias, AliasLoc, ColonColonLoc); if (Range.getBegin().isInvalid()) Range.setBegin(AliasLoc); Range.setEnd(ColonColonLoc); assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc) { Builder.MakeGlobal(Context, ColonColonLoc); Range = SourceRange(ColonColonLoc); assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange R) { Builder.MakeTrivial(Context, Qualifier, R); Range = R; } void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) { if (!Other) { Range = SourceRange(); Builder.Clear(); return; } Range = Other.getSourceRange(); Builder.Adopt(Other); } SourceLocation CXXScopeSpec::getLastQualifierNameLoc() const { if (!Builder.getRepresentation()) return SourceLocation(); return Builder.getTemporary().getLocalBeginLoc(); } NestedNameSpecifierLoc CXXScopeSpec::getWithLocInContext(ASTContext &Context) const { if (!Builder.getRepresentation()) return NestedNameSpecifierLoc(); return Builder.getWithLocInContext(Context); } /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, SourceLocation EllipsisLoc, ParamInfo *ArgInfo, unsigned NumArgs, unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, SourceLocation ConstQualifierLoc, SourceLocation VolatileQualifierLoc, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, SourceLocation ESpecLoc, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, - CachedTokens *ExceptionSpecTokens, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, ParsedType TrailingReturnType) { DeclaratorChunk I; I.Kind = Function; I.Loc = LocalRangeBegin; I.EndLoc = LocalRangeEnd; I.Fun.AttrList = 0; I.Fun.hasPrototype = hasProto; I.Fun.isVariadic = isVariadic; I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); I.Fun.DeleteArgInfo = false; I.Fun.TypeQuals = TypeQuals; I.Fun.NumArgs = NumArgs; I.Fun.ArgInfo = 0; I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef; I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); I.Fun.ConstQualifierLoc = ConstQualifierLoc.getRawEncoding(); I.Fun.VolatileQualifierLoc = VolatileQualifierLoc.getRawEncoding(); I.Fun.MutableLoc = MutableLoc.getRawEncoding(); I.Fun.ExceptionSpecType = ESpecType; I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding(); I.Fun.NumExceptions = 0; I.Fun.Exceptions = 0; I.Fun.NoexceptExpr = 0; I.Fun.TrailingReturnType = TrailingReturnType.getAsOpaquePtr(); // new[] an argument array if needed. if (NumArgs) { // If the 'InlineParams' in Declarator is unused and big enough, put our // parameter list there (in an effort to avoid new/delete traffic). If it // is already used (consider a function returning a function pointer) or too // small (function taking too many arguments), go to the heap. if (!TheDeclarator.InlineParamsUsed && NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) { I.Fun.ArgInfo = TheDeclarator.InlineParams; I.Fun.DeleteArgInfo = false; TheDeclarator.InlineParamsUsed = true; } else { I.Fun.ArgInfo = new DeclaratorChunk::ParamInfo[NumArgs]; I.Fun.DeleteArgInfo = true; } memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs); } // Check what exception specification information we should actually store. switch (ESpecType) { default: break; // By default, save nothing. case EST_Dynamic: // new[] an exception array if needed if (NumExceptions) { I.Fun.NumExceptions = NumExceptions; I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions]; for (unsigned i = 0; i != NumExceptions; ++i) { I.Fun.Exceptions[i].Ty = Exceptions[i]; I.Fun.Exceptions[i].Range = ExceptionRanges[i]; } } break; case EST_ComputedNoexcept: I.Fun.NoexceptExpr = NoexceptExpr; - break; - - case EST_Delayed: - I.Fun.ExceptionSpecTokens = ExceptionSpecTokens; break; } return I; } bool Declarator::isDeclarationOfFunction() const { for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { switch (DeclTypeInfo[i].Kind) { case DeclaratorChunk::Function: return true; case DeclaratorChunk::Paren: continue; case DeclaratorChunk::Pointer: case DeclaratorChunk::Reference: case DeclaratorChunk::Array: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: return false; } llvm_unreachable("Invalid type chunk"); } switch (DS.getTypeSpecType()) { case TST_atomic: case TST_auto: case TST_bool: case TST_char: case TST_char16: case TST_char32: case TST_class: case TST_decimal128: case TST_decimal32: case TST_decimal64: case TST_double: case TST_enum: case TST_error: case TST_float: case TST_half: case TST_int: case TST_int128: case TST_struct: case TST_union: case TST_unknown_anytype: case TST_unspecified: case TST_void: case TST_wchar: return false; case TST_decltype: case TST_typeofExpr: if (Expr *E = DS.getRepAsExpr()) return E->getType()->isFunctionType(); return false; case TST_underlyingType: case TST_typename: case TST_typeofType: { QualType QT = DS.getRepAsType().get(); if (QT.isNull()) return false; if (const LocInfoType *LIT = dyn_cast(QT)) QT = LIT->getType(); if (QT.isNull()) return false; return QT->isFunctionType(); } } llvm_unreachable("Invalid TypeSpecType!"); } /// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this /// declaration specifier includes. /// unsigned DeclSpec::getParsedSpecifiers() const { unsigned Res = 0; if (StorageClassSpec != SCS_unspecified || SCS_thread_specified) Res |= PQ_StorageClassSpecifier; if (TypeQualifiers != TQ_unspecified) Res |= PQ_TypeQualifier; if (hasTypeSpecifier()) Res |= PQ_TypeSpecifier; if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified) Res |= PQ_FunctionSpecifier; return Res; } template static bool BadSpecifier(T TNew, T TPrev, const char *&PrevSpec, unsigned &DiagID) { PrevSpec = DeclSpec::getSpecifierName(TPrev); DiagID = (TNew == TPrev ? diag::ext_duplicate_declspec : diag::err_invalid_decl_spec_combination); return true; } const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { switch (S) { case DeclSpec::SCS_unspecified: return "unspecified"; case DeclSpec::SCS_typedef: return "typedef"; case DeclSpec::SCS_extern: return "extern"; case DeclSpec::SCS_static: return "static"; case DeclSpec::SCS_auto: return "auto"; case DeclSpec::SCS_register: return "register"; case DeclSpec::SCS_private_extern: return "__private_extern__"; case DeclSpec::SCS_mutable: return "mutable"; } llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TSW W) { switch (W) { case TSW_unspecified: return "unspecified"; case TSW_short: return "short"; case TSW_long: return "long"; case TSW_longlong: return "long long"; } llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TSC C) { switch (C) { case TSC_unspecified: return "unspecified"; case TSC_imaginary: return "imaginary"; case TSC_complex: return "complex"; } llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TSS S) { switch (S) { case TSS_unspecified: return "unspecified"; case TSS_signed: return "signed"; case TSS_unsigned: return "unsigned"; } llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { switch (T) { case DeclSpec::TST_unspecified: return "unspecified"; case DeclSpec::TST_void: return "void"; case DeclSpec::TST_char: return "char"; case DeclSpec::TST_wchar: return "wchar_t"; case DeclSpec::TST_char16: return "char16_t"; case DeclSpec::TST_char32: return "char32_t"; case DeclSpec::TST_int: return "int"; case DeclSpec::TST_int128: return "__int128"; case DeclSpec::TST_half: return "half"; case DeclSpec::TST_float: return "float"; case DeclSpec::TST_double: return "double"; case DeclSpec::TST_bool: return "_Bool"; case DeclSpec::TST_decimal32: return "_Decimal32"; case DeclSpec::TST_decimal64: return "_Decimal64"; case DeclSpec::TST_decimal128: return "_Decimal128"; case DeclSpec::TST_enum: return "enum"; case DeclSpec::TST_class: return "class"; case DeclSpec::TST_union: return "union"; case DeclSpec::TST_struct: return "struct"; case DeclSpec::TST_typename: return "type-name"; case DeclSpec::TST_typeofType: case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_atomic: return "_Atomic"; case DeclSpec::TST_error: return "(error)"; } llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TQ T) { switch (T) { case DeclSpec::TQ_unspecified: return "unspecified"; case DeclSpec::TQ_const: return "const"; case DeclSpec::TQ_restrict: return "restrict"; case DeclSpec::TQ_volatile: return "volatile"; } llvm_unreachable("Unknown typespec!"); } bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { // OpenCL 1.1 6.8g: "The extern, static, auto and register storage-class // specifiers are not supported." // It seems sensible to prohibit private_extern too // The cl_clang_storage_class_specifiers extension enables support for // these storage-class specifiers. if (S.getLangOpts().OpenCL && !S.getOpenCLOptions().cl_clang_storage_class_specifiers) { switch (SC) { case SCS_extern: case SCS_private_extern: case SCS_auto: case SCS_register: case SCS_static: DiagID = diag::err_not_opencl_storage_class_specifier; PrevSpec = getSpecifierName(SC); return true; default: break; } } if (StorageClassSpec != SCS_unspecified) { // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode. bool isInvalid = true; if (TypeSpecType == TST_unspecified && S.getLangOpts().CPlusPlus) { if (SC == SCS_auto) return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID); if (StorageClassSpec == SCS_auto) { isInvalid = SetTypeSpecType(TST_auto, StorageClassSpecLoc, PrevSpec, DiagID); assert(!isInvalid && "auto SCS -> TST recovery failed"); } } // Changing storage class is allowed only if the previous one // was the 'extern' that is part of a linkage specification and // the new storage class is 'typedef'. if (isInvalid && !(SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern && SC == SCS_typedef)) return BadSpecifier(SC, (SCS)StorageClassSpec, PrevSpec, DiagID); } StorageClassSpec = SC; StorageClassSpecLoc = Loc; assert((unsigned)SC == StorageClassSpec && "SCS constants overflow bitfield"); return false; } bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { if (SCS_thread_specified) { PrevSpec = "__thread"; DiagID = diag::ext_duplicate_declspec; return true; } SCS_thread_specified = true; SCS_threadLoc = Loc; return false; } /// These methods set the specified attribute of the DeclSpec, but return true /// and ignore the request if invalid (e.g. "extern" then "auto" is /// specified). bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { // Overwrite TSWLoc only if TypeSpecWidth was unspecified, so that // for 'long long' we will keep the source location of the first 'long'. if (TypeSpecWidth == TSW_unspecified) TSWLoc = Loc; // Allow turning long -> long long. else if (W != TSW_longlong || TypeSpecWidth != TSW_long) return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID); TypeSpecWidth = W; if (TypeAltiVecVector && !TypeAltiVecBool && ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); DiagID = diag::warn_vector_long_decl_spec_combination; return true; } return false; } bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { if (TypeSpecComplex != TSC_unspecified) return BadSpecifier(C, (TSC)TypeSpecComplex, PrevSpec, DiagID); TypeSpecComplex = C; TSCLoc = Loc; return false; } bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { if (TypeSpecSign != TSS_unspecified) return BadSpecifier(S, (TSS)TypeSpecSign, PrevSpec, DiagID); TypeSpecSign = S; TSSLoc = Loc; return false; } bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, ParsedType Rep) { return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep); } bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, SourceLocation TagNameLoc, const char *&PrevSpec, unsigned &DiagID, ParsedType Rep) { assert(isTypeRep(T) && "T does not store a type"); assert(Rep && "no type provided!"); if (TypeSpecType != TST_unspecified) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); DiagID = diag::err_invalid_decl_spec_combination; return true; } TypeSpecType = T; TypeRep = Rep; TSTLoc = TagKwLoc; TSTNameLoc = TagNameLoc; TypeSpecOwned = false; return false; } bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, Expr *Rep) { assert(isExprRep(T) && "T does not store an expr"); assert(Rep && "no expression provided!"); if (TypeSpecType != TST_unspecified) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); DiagID = diag::err_invalid_decl_spec_combination; return true; } TypeSpecType = T; ExprRep = Rep; TSTLoc = Loc; TSTNameLoc = Loc; TypeSpecOwned = false; return false; } bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, Decl *Rep, bool Owned) { return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep, Owned); } bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, SourceLocation TagNameLoc, const char *&PrevSpec, unsigned &DiagID, Decl *Rep, bool Owned) { assert(isDeclRep(T) && "T does not store a decl"); // Unlike the other cases, we don't assert that we actually get a decl. if (TypeSpecType != TST_unspecified) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); DiagID = diag::err_invalid_decl_spec_combination; return true; } TypeSpecType = T; DeclRep = Rep; TSTLoc = TagKwLoc; TSTNameLoc = TagNameLoc; TypeSpecOwned = Owned; return false; } bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { assert(!isDeclRep(T) && !isTypeRep(T) && !isExprRep(T) && "rep required for these type-spec kinds!"); if (TypeSpecType != TST_unspecified) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); DiagID = diag::err_invalid_decl_spec_combination; return true; } TSTLoc = Loc; TSTNameLoc = Loc; if (TypeAltiVecVector && (T == TST_bool) && !TypeAltiVecBool) { TypeAltiVecBool = true; return false; } TypeSpecType = T; TypeSpecOwned = false; if (TypeAltiVecVector && !TypeAltiVecBool && (TypeSpecType == TST_double)) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); DiagID = diag::err_invalid_vector_decl_spec; return true; } return false; } bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { if (TypeSpecType != TST_unspecified) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); DiagID = diag::err_invalid_vector_decl_spec_combination; return true; } TypeAltiVecVector = isAltiVecVector; AltiVecLoc = Loc; return false; } bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { if (!TypeAltiVecVector || TypeAltiVecPixel || (TypeSpecType != TST_unspecified)) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); DiagID = diag::err_invalid_pixel_decl_spec_combination; return true; } TypeAltiVecPixel = isAltiVecPixel; TSTLoc = Loc; TSTNameLoc = Loc; return false; } bool DeclSpec::SetTypeSpecError() { TypeSpecType = TST_error; TypeSpecOwned = false; TSTLoc = SourceLocation(); TSTNameLoc = SourceLocation(); return false; } bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const LangOptions &Lang) { // Duplicates turn into warnings pre-C99. if ((TypeQualifiers & T) && !Lang.C99) return BadSpecifier(T, T, PrevSpec, DiagID); TypeQualifiers |= T; switch (T) { default: llvm_unreachable("Unknown type qualifier!"); case TQ_const: TQ_constLoc = Loc; break; case TQ_restrict: TQ_restrictLoc = Loc; break; case TQ_volatile: TQ_volatileLoc = Loc; break; } return false; } bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { // 'inline inline' is ok. FS_inline_specified = true; FS_inlineLoc = Loc; return false; } bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { // 'virtual virtual' is ok. FS_virtual_specified = true; FS_virtualLoc = Loc; return false; } bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { // 'explicit explicit' is ok. FS_explicit_specified = true; FS_explicitLoc = Loc; return false; } bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { if (Friend_specified) { PrevSpec = "friend"; DiagID = diag::ext_duplicate_declspec; return true; } Friend_specified = true; FriendLoc = Loc; return false; } bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { if (isModulePrivateSpecified()) { PrevSpec = "__module_private__"; DiagID = diag::ext_duplicate_declspec; return true; } ModulePrivateLoc = Loc; return false; } bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { // 'constexpr constexpr' is ok. Constexpr_specified = true; ConstexprLoc = Loc; return false; } void DeclSpec::setProtocolQualifiers(Decl * const *Protos, unsigned NP, SourceLocation *ProtoLocs, SourceLocation LAngleLoc) { if (NP == 0) return; ProtocolQualifiers = new Decl*[NP]; ProtocolLocs = new SourceLocation[NP]; memcpy((void*)ProtocolQualifiers, Protos, sizeof(Decl*)*NP); memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP); NumProtocolQualifiers = NP; ProtocolLAngleLoc = LAngleLoc; } void DeclSpec::SaveWrittenBuiltinSpecs() { writtenBS.Sign = getTypeSpecSign(); writtenBS.Width = getTypeSpecWidth(); writtenBS.Type = getTypeSpecType(); // Search the list of attributes for the presence of a mode attribute. writtenBS.ModeAttr = false; AttributeList* attrs = getAttributes().getList(); while (attrs) { if (attrs->getKind() == AttributeList::AT_mode) { writtenBS.ModeAttr = true; break; } attrs = attrs->getNext(); } } void DeclSpec::SaveStorageSpecifierAsWritten() { if (SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern) // If 'extern' is part of a linkage specification, // then it is not a storage class "as written". StorageClassSpecAsWritten = SCS_unspecified; else StorageClassSpecAsWritten = StorageClassSpec; } /// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); SaveStorageSpecifierAsWritten(); // Check the type specifier components first. // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { // Sign specifiers are not allowed with vector bool. (PIM 2.1) if (TypeSpecSign != TSS_unspecified) { Diag(D, TSSLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSS)TypeSpecSign); } // Only char/int are valid with vector bool. (PIM 2.1) if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && (TypeSpecType != TST_int)) || TypeAltiVecPixel) { Diag(D, TSTLoc, diag::err_invalid_vector_bool_decl_spec) << (TypeAltiVecPixel ? "__pixel" : getSpecifierName((TST)TypeSpecType)); } // Only 'short' is valid with vector bool. (PIM 2.1) if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short)) Diag(D, TSWLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSW)TypeSpecWidth); // Elements of vector bool are interpreted as unsigned. (PIM 2.1) if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || (TypeSpecWidth != TSW_unspecified)) TypeSpecSign = TSS_unsigned; } if (TypeAltiVecPixel) { //TODO: perform validation TypeSpecType = TST_int; TypeSpecSign = TSS_unsigned; TypeSpecWidth = TSW_short; TypeSpecOwned = false; } } // signed/unsigned are only valid with int/char/wchar_t. if (TypeSpecSign != TSS_unspecified) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 && TypeSpecType != TST_char && TypeSpecType != TST_wchar) { Diag(D, TSSLoc, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType); // signed double -> double. TypeSpecSign = TSS_unspecified; } } // Validate the width of the type. switch (TypeSpecWidth) { case TSW_unspecified: break; case TSW_short: // short int case TSW_longlong: // long long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { Diag(D, TSWLoc, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec : diag::err_invalid_longlong_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; TypeSpecOwned = false; } break; case TSW_long: // long double, long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { Diag(D, TSWLoc, diag::err_invalid_long_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; TypeSpecOwned = false; } break; } // TODO: if the implementation does not implement _Complex or _Imaginary, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { Diag(D, TSCLoc, diag::ext_plain_complex) << FixItHint::CreateInsertion( PP.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. if (!PP.getLangOpts().CPlusPlus) Diag(D, TSTLoc, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { Diag(D, TSCLoc, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecComplex = TSC_unspecified; } } // If no type specifier was provided and we're parsing a language where // the type specifier is not optional, but we got 'auto' as a storage // class specifier, then assume this is an attempt to use C++0x's 'auto' // type specifier. // FIXME: Does Microsoft really support implicit int in C++? if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().MicrosoftExt && TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) { TypeSpecType = TST_auto; StorageClassSpec = StorageClassSpecAsWritten = SCS_unspecified; TSTLoc = TSTNameLoc = StorageClassSpecLoc; StorageClassSpecLoc = SourceLocation(); } // Diagnose if we've recovered from an ill-formed 'auto' storage class // specifier in a pre-C++0x dialect of C++. if (!PP.getLangOpts().CPlusPlus0x && TypeSpecType == TST_auto) Diag(D, TSTLoc, diag::ext_auto_type_specifier); if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus0x && StorageClassSpec == SCS_auto) Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class) << FixItHint::CreateRemoval(StorageClassSpecLoc); if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32) Diag(D, TSTLoc, diag::warn_cxx98_compat_unicode_type) << (TypeSpecType == TST_char16 ? "char16_t" : "char32_t"); if (Constexpr_specified) Diag(D, ConstexprLoc, diag::warn_cxx98_compat_constexpr); // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. if (isFriendSpecified() && getStorageClassSpec()) { DeclSpec::SCS SC = getStorageClassSpec(); const char *SpecName = getSpecifierName(SC); SourceLocation SCLoc = getStorageClassSpecLoc(); SourceLocation SCEndLoc = SCLoc.getLocWithOffset(strlen(SpecName)); Diag(D, SCLoc, diag::err_friend_storage_spec) << SpecName << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); ClearStorageClassSpecs(); } assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. // 'data definition has no type or storage class'? } bool DeclSpec::isMissingDeclaratorOk() { TST tst = getTypeSpecType(); return isDeclRep(tst) && getRepAsDecl() != 0 && StorageClassSpec != DeclSpec::SCS_typedef; } void UnqualifiedId::clear() { Kind = IK_Identifier; Identifier = 0; StartLocation = SourceLocation(); EndLocation = SourceLocation(); } void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, OverloadedOperatorKind Op, SourceLocation SymbolLocations[3]) { Kind = IK_OperatorFunctionId; StartLocation = OperatorLoc; EndLocation = OperatorLoc; OperatorFunctionId.Operator = Op; for (unsigned I = 0; I != 3; ++I) { OperatorFunctionId.SymbolLocations[I] = SymbolLocations[I].getRawEncoding(); if (SymbolLocations[I].isValid()) EndLocation = SymbolLocations[I]; } } bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, const char *&PrevSpec) { LastLocation = Loc; if (Specifiers & VS) { PrevSpec = getSpecifierName(VS); return true; } Specifiers |= VS; switch (VS) { default: llvm_unreachable("Unknown specifier!"); case VS_Override: VS_overrideLoc = Loc; break; case VS_Final: VS_finalLoc = Loc; break; } return false; } const char *VirtSpecifiers::getSpecifierName(Specifier VS) { switch (VS) { default: llvm_unreachable("Unknown specifier"); case VS_Override: return "override"; case VS_Final: return "final"; } } Index: vendor/clang/dist/lib/Sema/SemaDecl.cpp =================================================================== --- vendor/clang/dist/lib/Sema/SemaDecl.cpp (revision 235808) +++ vendor/clang/dist/lib/Sema/SemaDecl.cpp (revision 235809) @@ -1,10477 +1,10462 @@ //===--- 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 "clang/Sema/SemaInternal.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.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/AST/CharUnits.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" // FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/ModuleLoader.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) : AllowInvalidDecl(AllowInvalid) { WantExpressionKeywords = false; WantCXXNamedCasts = false; WantRemainingKeywords = false; } virtual bool ValidateCandidate(const TypoCorrection &candidate) { if (NamedDecl *ND = candidate.getCorrectionDecl()) return (isa(ND) || isa(ND)) && (AllowInvalidDecl || !ND->isInvalidDecl()); else return candidate.isKeyword(); } private: bool AllowInvalidDecl; }; } /// \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. /// /// If name lookup results in an ambiguity, this routine will complain /// and then return NULL. ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr, bool IsCtorOrDtorName, bool WantNontrivialTypeSourceInfo, IdentifierInfo **CorrectedII) { // Determine where we will perform name lookup. DeclContext *LookupCtx = 0; 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 ParsedType(); // 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 ParsedType(); } if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS, LookupCtx)) return ParsedType(); } // 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); } NamedDecl *IIDecl = 0; switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: if (CorrectedII) { TypeNameValidatorCCC Validator(true); TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(), Kind, S, SS, Validator); 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, ParsedType(), false, Template, MemberOfUnknownSpecialization))) { ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr, isClassName, HasTrailingDot, ObjectTypePtr, IsCtorOrDtorName, WantNontrivialTypeSourceInfo); if (Ty) { std::string CorrectedStr(Correction.getAsString(getLangOpts())); std::string CorrectedQuotedStr( Correction.getQuoted(getLangOpts())); Diag(NameLoc, diag::err_unknown_typename_suggest) << Result.getLookupName() << CorrectedQuotedStr << FixItHint::CreateReplacement(SourceRange(NameLoc), CorrectedStr); if (NamedDecl *FirstDecl = Correction.getCorrectionDecl()) Diag(FirstDecl->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; 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 ParsedType(); 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 ParsedType(); } // 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)) { 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 ParsedType(); } // 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)) { DiagnoseUseOfDecl(IIDecl, NameLoc); if (T.isNull()) T = Context.getTypeDeclType(TD); // 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) { 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); } } } else if (ObjCInterfaceDecl *IDecl = dyn_cast(IIDecl)) { (void)DiagnoseUseOfDecl(IDecl, NameLoc); if (!HasTrailingDot) T = Context.getObjCInterfaceType(IDecl); } if (T.isNull()) { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); return ParsedType(); } return ParsedType::make(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_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_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()) { const Type *Ty = SS->getScopeRep()->getAsType(); CXXRecordDecl *RD = cast(CurContext); for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base->getType())) return true; return S->isFunctionPrototypeScope(); } return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType) { // We don't have anything to suggest (yet). SuggestedType = ParsedType(); // 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. TypeNameValidatorCCC Validator(false); if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc), LookupOrdinaryName, S, SS, Validator)) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts())); if (Corrected.isKeyword()) { // We corrected to a keyword. // FIXME: Actually recover with the keyword we suggest, and emit a fix-it. Diag(IILoc, diag::err_unknown_typename_suggest) << &II << CorrectedQuotedStr; } else { NamedDecl *Result = Corrected.getCorrectionDecl(); // We found a similarly-named type or interface; suggest that. if (!SS || !SS->isSet()) Diag(IILoc, diag::err_unknown_typename_suggest) << &II << CorrectedQuotedStr << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_unknown_nested_typename_suggest) << &II << DC << CorrectedQuotedStr << SS->getRange() << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); else llvm_unreachable("could not have corrected a typo here"); Diag(Result->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS, false, false, ParsedType(), /*IsCtorOrDtorName=*/false, /*NonTrivialTypeSourceInfo=*/true); } return true; } if (getLangOpts().CPlusPlus) { // 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, ParsedType(), true, TemplateResult, MemberOfUnknownSpecialization) == TNK_Type_template) { TemplateName TplName = TemplateResult.getAsVal(); Diag(IILoc, diag::err_template_missing_args) << TplName; if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) { Diag(TplDecl->getLocation(), diag::note_template_decl_here) << TplDecl->getTemplateParameters()->getSourceRange(); } return true; } } // 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, diag::err_unknown_typename) << &II; else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_typename_nested_not_found) << &II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; if (getLangOpts().MicrosoftMode && isMicrosoftMissingTypename(SS, S)) DiagID = diag::warn_typename_missing; Diag(SS->getRange().getBegin(), DiagID) << (NestedNameSpecifier *)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"); } return true; } /// \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; } Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken) { DeclarationNameInfo NameInfo(Name, NameLoc); ObjCMethodDecl *CurMethod = getCurMethodDecl(); if (NextToken.is(tok::coloncolon)) { BuildCXXNestedNameSpecifier(S, *Name, NameLoc, NextToken.getLocation(), QualType(), false, SS, 0, false); } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); LookupParsedName(Result, S, &SS, !CurMethod); // 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 forget to write "enum", // "struct", or "union". if (!getLangOpts().CPlusPlus && !SecondTry) { Result.clear(LookupTagName); LookupParsedName(Result, S, &SS); if (TagDecl *Tag = Result.getAsSingle()) { const char *TagName = 0; const char *FixItTagName = 0; switch (Tag->getTagKind()) { case TTK_Class: TagName = "class"; FixItTagName = "class "; break; case TTK_Enum: TagName = "enum"; FixItTagName = "enum "; break; case TTK_Struct: TagName = "struct"; FixItTagName = "struct "; break; case TTK_Union: TagName = "union"; FixItTagName = "union "; break; } Diag(NameLoc, diag::err_use_of_tag_name_without_tag) << Name << TagName << getLangOpts().CPlusPlus << FixItHint::CreateInsertion(NameLoc, FixItTagName); break; } Result.clear(LookupOrdinaryName); } // Perform typo correction to determine if there is another name that is // close to this name. if (!SecondTry) { SecondTry = true; CorrectionCandidateCallback DefaultValidator; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, &SS, DefaultValidator)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; std::string CorrectedStr(Corrected.getAsString(getLangOpts())); std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts())); NamedDecl *FirstDecl = Corrected.getCorrectionDecl(); NamedDecl *UnderlyingFirstDecl = FirstDecl? FirstDecl->getUnderlyingDecl() : 0; 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()) Diag(NameLoc, UnqualifiedDiag) << Name << CorrectedQuotedStr << FixItHint::CreateReplacement(NameLoc, CorrectedStr); else Diag(NameLoc, QualifiedDiag) << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange() << FixItHint::CreateReplacement(NameLoc, CorrectedStr); // Update the name, so that the caller has the new name. Name = Corrected.getCorrectionAsIdentifierInfo(); // Typo correction corrected to a keyword. if (Corrected.isKeyword()) return Corrected.getCorrectionAsIdentifierInfo(); // Also update the LookupResult... // FIXME: This should probably go away at some point Result.clear(); Result.setLookupName(Corrected.getCorrection()); if (FirstDecl) { Result.addDecl(FirstDecl); Diag(FirstDecl->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; } // 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 move(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 BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*TemplateArgs=*/0); } 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; 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); 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 NameClassification::TypeTemplate(Template); } } NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); if (TypeDecl *Type = dyn_cast(FirstDecl)) { DiagnoseUseOfDecl(Type, NameLoc); QualType T = Context.getTypeDeclType(Type); 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); } if (!Result.empty() && (*Result.begin())->isCXXClassMember()) return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0); bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); return BuildDeclarationNameExpr(SS, Result, ADL); } // 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. if (isa(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!"); } /// 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 = (DeclContext*) Ancestor->getEntity(); // We don't need to do anything with the scope, which is going to // disappear. } void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { FunctionDecl *FD = dyn_cast(D); if (FunctionTemplateDecl *TFD = dyn_cast_or_null(D)) { // We assume that the caller has already called // ActOnReenterTemplateScope FD = TFD->getTemplatedDecl(); } 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() && ((DeclContext *)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++. // Out-of-line variable and function definitions shouldn't even in C. if ((getLangOpts().CPlusPlus || isa(D) || isa(D)) && D->isOutOfLine() && !D->getDeclContext()->getRedeclContext()->Equals( D->getLexicalDeclContext()->getRedeclContext())) 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 ExplicitInstantiationOrSpecialization) { return IdResolver.isDeclInScope(D, Ctx, Context, S, ExplicitInstantiationOrSpecialization); } Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) { DeclContext *TargetDC = DC->getPrimaryContext(); do { if (DeclContext *ScopeDC = (DeclContext*) S->getEntity()) if (ScopeDC->getPrimaryContext() == TargetDC) return S; } while ((S = S->getParent())); return 0; } 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 ExplicitInstantiationOrSpecialization) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization)) 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; } bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { assert(D); if (D->isInvalidDecl() || D->isUsed() || D->hasAttr()) return false; // Ignore 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; if (const CXXMethodDecl *MD = dyn_cast(FD)) { if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD)) return false; } else { // 'static inline' functions are used in headers; don't warn. if (FD->getStorageClass() == SC_Static && FD->isInlineSpecified()) return false; } if (FD->doesThisDeclarationHaveABody() && Context.DeclMustBeEmitted(FD)) return false; } else if (const VarDecl *VD = dyn_cast(D)) { if (!VD->isFileVarDecl() || VD->getType().isConstant(Context) || Context.DeclMustBeEmitted(VD)) return false; if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; } else { return false; } // Only warn for unused decls internal to the translation unit. if (D->getLinkage() == ExternalLinkage) return false; return true; } void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { if (!D) return; if (const FunctionDecl *FD = dyn_cast(D)) { const FunctionDecl *First = FD->getFirstDeclaration(); if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First)) return; // First should already be in the vector. } if (const VarDecl *VD = dyn_cast(D)) { const VarDecl *First = VD->getFirstDeclaration(); 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()) return false; if (isa(D)) return true; // White-list anything that isn't a local variable. if (!isa(D) || isa(D) || isa(D) || !D->getDeclContext()->isFunctionOrMethod()) 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. QualType Ty = VD->getType(); // Only look at the outermost level of typedef. if (const TypedefType *TT = dyn_cast(Ty)) { 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; 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()) return false; if (const Expr *Init = VD->getInit()) { const CXXConstructExpr *Construct = dyn_cast(Init); if (Construct && !Construct->isElidable()) { CXXConstructorDecl *CD = Construct->getConstructor(); if (!CD->isTrivial()) 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)); } return; } /// DiagnoseUnusedDecl - Emit warnings about declarations that are not used /// unless they are marked attr(unused). void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { FixItHint Hint; if (!ShouldDiagnoseUnusedDecl(D)) return; 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. if (L->getStmt() == 0) S.Diag(L->getLocation(), diag::err_undeclared_label_use) <getDeclName(); } void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (S->decl_empty()) return; assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && "Scope shouldn't contain decls!"); for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); I != E; ++I) { Decl *TmpD = (*I); 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->hasErrorOccurred()) DiagnoseUnusedDecl(D); // 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. IdResolver.RemoveDecl(D); } } void Sema::ActOnStartFunctionDeclarator() { ++InFunctionDeclarator; } void Sema::ActOnEndFunctionDeclarator() { assert(InFunctionDeclarator); --InFunctionDeclarator; } /// \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 TypoCorrection 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. DeclFilterCCC Validator; if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, TUScope, NULL, Validator)) { IDecl = C.getCorrectionDeclAs(); Diag(IdLoc, diag::err_undef_interface_suggest) << Id << IDecl->getDeclName() << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString()); Diag(IDecl->getLocation(), diag::note_previous_decl) << IDecl->getDeclName(); 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() && ((DeclContext *)S->getEntity())->isTransparentContext()) || (S->isClassScope() && !getLangOpts().CPlusPlus)) S = S->getParent(); return S; } /// 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 bid, Scope *S, bool ForRedeclaration, SourceLocation Loc) { Builtin::ID BID = (Builtin::ID)bid; ASTContext::GetBuiltinTypeError Error; QualType R = Context.GetBuiltinType(BID, Error); switch (Error) { case ASTContext::GE_None: // Okay break; case ASTContext::GE_Missing_stdio: if (ForRedeclaration) Diag(Loc, diag::warn_implicit_decl_requires_stdio) << Context.BuiltinInfo.GetName(BID); return 0; case ASTContext::GE_Missing_setjmp: if (ForRedeclaration) Diag(Loc, diag::warn_implicit_decl_requires_setjmp) << Context.BuiltinInfo.GetName(BID); return 0; case ASTContext::GE_Missing_ucontext: if (ForRedeclaration) Diag(Loc, diag::warn_implicit_decl_requires_ucontext) << Context.BuiltinInfo.GetName(BID); return 0; } if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) { Diag(Loc, diag::ext_implicit_lib_function_decl) << Context.BuiltinInfo.GetName(BID) << R; if (Context.BuiltinInfo.getHeaderName(BID) && Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl, Loc) != DiagnosticsEngine::Ignored) Diag(Loc, diag::note_please_include_header) << Context.BuiltinInfo.getHeaderName(BID) << Context.BuiltinInfo.GetName(BID); } FunctionDecl *New = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), Loc, Loc, II, R, /*TInfo=*/0, SC_Extern, SC_None, false, /*hasPrototype=*/true); 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->getNumArgs(); i != e; ++i) { ParmVarDecl *parm = ParmVarDecl::Create(Context, New, SourceLocation(), SourceLocation(), 0, FT->getArgType(i), /*TInfo=*/0, SC_None, SC_None, 0); parm->setScopeInfo(0, i); Params.push_back(parm); } New->setParams(Params); } AddKnownFunctionAttributes(New); // 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 = Context.getTranslationUnitDecl(); PushOnScopeChains(New, TUScope); CurContext = SavedContext; return New; } 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()) Diag(Old->getLocation(), diag::note_previous_definition); 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()) Diag(Old->getLocation(), diag::note_previous_definition); 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(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; Context.setObjCIdRedefinitionType(New->getUnderlyingType()); // 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()) Diag(OldD->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } // If the old declaration is invalid, just give up here. if (Old->isInvalidDecl()) return New->setInvalidDecl(); // 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 if the old // declaration was a typedef. if (TypedefNameDecl *Typedef = dyn_cast(Old)) New->setPreviousDeclaration(Typedef); 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(); Diag(Old->getLocation(), diag::note_previous_definition); 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() && (Context.getSourceManager().isInSystemHeader(Old->getLocation()) || Context.getSourceManager().isInSystemHeader(New->getLocation()))) return; Diag(New->getLocation(), diag::warn_redefinition_of_typedef) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return; } /// 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 (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i) 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; } /// mergeDeclAttributes - Copy attributes from the Old decl to the New one. void Sema::mergeDeclAttributes(Decl *New, Decl *Old, bool MergeDeprecation) { 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 (specific_attr_iterator i = Old->specific_attr_begin(), e = Old->specific_attr_end(); i != e; ++i) { // Ignore deprecated/unavailable/availability attributes if requested. if (!MergeDeprecation && (isa(*i) || isa(*i) || isa(*i))) continue; if (!DeclHasAttr(New, *i)) { InheritableAttr *newAttr = cast((*i)->clone(Context)); newAttr->setInherited(true); New->addAttr(newAttr); 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, ASTContext &C) { 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 (specific_attr_iterator i = oldDecl->specific_attr_begin(), e = oldDecl->specific_attr_end(); i != e; ++i) { if (!DeclHasAttr(newDecl, *i)) { InheritableAttr *newAttr = cast((*i)->clone(C)); newAttr->setInherited(true); newDecl->addAttr(newAttr); foundAny = true; } } if (!foundAny) newDecl->dropAttrs(); } namespace { /// Used in MergeFunctionDecl to keep track of function parameters in /// C. struct GNUCompatibleParamWarning { ParmVarDecl *OldParm; ParmVarDecl *NewParm; QualType PromotedType; }; } /// 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; } /// 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); } /// 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, Decl *OldD, Scope *S) { // Verify the old decl was also a function. FunctionDecl *Old = 0; if (FunctionTemplateDecl *OldFunctionTemplate = dyn_cast(OldD)) Old = OldFunctionTemplate->getTemplatedDecl(); else Old = dyn_cast(OldD); if (!Old) { if (UsingShadowDecl *Shadow = dyn_cast(OldD)) { Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); Diag(Shadow->getTargetDecl()->getLocation(), diag::note_using_decl_target); Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; return true; } Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); Diag(OldD->getLocation(), diag::note_previous_definition); return true; } // Determine whether the previous declaration was a definition, // implicit declaration, or a declaration. diag::kind PrevDiag; if (Old->isThisDeclarationADefinition()) PrevDiag = diag::note_previous_definition; else if (Old->isImplicit()) PrevDiag = diag::note_previous_implicit_declaration; else PrevDiag = diag::note_previous_declaration; QualType OldQType = Context.getCanonicalType(Old->getType()); QualType NewQType = Context.getCanonicalType(New->getType()); // Don't complain about this if we're in GNU89 mode and the old function // is an extern inline function. if (!isa(New) && !isa(Old) && New->getStorageClass() == SC_Static && Old->getStorageClass() != SC_Static && !canRedefineFunction(Old, getLangOpts())) { if (getLangOpts().MicrosoftExt) { Diag(New->getLocation(), diag::warn_static_non_static) << New; Diag(Old->getLocation(), PrevDiag); } else { Diag(New->getLocation(), diag::err_static_non_static) << New; Diag(Old->getLocation(), PrevDiag); return true; } } // If a function is first declared with a calling convention, but is // later declared or defined without one, the second decl assumes the // calling convention of the first. // // For the new decl, we have to look at the NON-canonical type to tell the // difference between a function that really doesn't have a calling // convention and one that is declared cdecl. That's because in // canonicalization (see ASTContext.cpp), cdecl is canonicalized away // because it is the default calling convention. // // Note also that we DO NOT return at this point, because we still have // other tests to run. const FunctionType *OldType = cast(OldQType); const FunctionType *NewType = New->getType()->getAs(); FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); bool RequiresAdjustment = false; if (OldTypeInfo.getCC() != CC_Default && NewTypeInfo.getCC() == CC_Default) { NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); RequiresAdjustment = true; } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), NewTypeInfo.getCC())) { // Calling conventions really aren't compatible, so complain. Diag(New->getLocation(), diag::err_cconv_change) << FunctionType::getNameForCallConv(NewTypeInfo.getCC()) << (OldTypeInfo.getCC() == CC_Default) << (OldTypeInfo.getCC() == CC_Default ? "" : FunctionType::getNameForCallConv(OldTypeInfo.getCC())); Diag(Old->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(Old->getLocation(), 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_returns_retained_mismatch); Diag(Old->getLocation(), diag::note_previous_declaration); return true; } NewTypeInfo = NewTypeInfo.withProducesResult(true); RequiresAdjustment = true; } if (RequiresAdjustment) { NewType = Context.adjustFunctionType(NewType, NewTypeInfo); New->setType(QualType(NewType, 0)); NewQType = Context.getCanonicalType(New->getType()); } if (getLangOpts().CPlusPlus) { // (C++98 13.1p2): // Certain function declarations cannot be overloaded: // -- Function declarations that differ only in the return type // cannot be overloaded. QualType OldReturnType = OldType->getResultType(); QualType NewReturnType = cast(NewQType)->getResultType(); QualType ResQT; if (OldReturnType != NewReturnType) { if (NewReturnType->isObjCObjectPointerType() && OldReturnType->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; else Diag(New->getLocation(), diag::err_ovl_diff_return_type); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); return true; } else NewQType = ResQT; } 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 CXMethodDecls referring to the same function will be injected. // We don't want a redeclartion 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(Old->getLocation(), 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. 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); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); // 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->isExplicitlyDefaulted()) { Diag(NewMethod->getLocation(), diag::err_definition_of_explicitly_defaulted_member) << getSpecialMember(OldMethod); return true; } } // (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()) { assert(OldQType == QualType(OldType, 0)); const FunctionType *OldTypeForComparison = Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true)); OldQTypeForComparison = QualType(OldTypeForComparison, 0); assert(OldQTypeForComparison.isCanonical()); } if (OldQTypeForComparison == NewQType) return MergeCompatibleFunctionDecls(New, Old, S); // 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 = 0; if (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->arg_type_begin(), OldProto->arg_type_end()); NewQType = Context.getFunctionType(NewFuncType->getResultType(), ParamTypes.data(), ParamTypes.size(), OldProto->getExtProtoInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); // Synthesize a parameter for each argument type. SmallVector Params; for (FunctionProtoType::arg_type_iterator ParamType = OldProto->arg_type_begin(), ParamEnd = OldProto->arg_type_end(); ParamType != ParamEnd; ++ParamType) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(), SourceLocation(), 0, *ParamType, /*TInfo=*/0, SC_None, SC_None, 0); Param->setScopeInfo(0, Params.size()); Param->setImplicit(); Params.push_back(Param); } New->setParams(Params); } return MergeCompatibleFunctionDecls(New, Old, S); } // 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->getResultType(), NewProto->getResultType()); 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->getArgType(Idx))) { ArgTypes.push_back(NewParm->getType()); } else if (Context.typesAreCompatible(OldParm->getType(), NewParm->getType(), /*CompareUnqualified=*/true)) { GNUCompatibleParamWarning Warn = { OldParm, NewParm, NewProto->getArgType(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); } New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0], ArgTypes.size(), OldProto->getExtProtoInfo())); return MergeCompatibleFunctionDecls(New, Old, S); } // Fall through to diagnose conflicting types. } // A function that has already been declared has been redeclared or defined // with a different type- show appropriate diagnostic if (unsigned BuiltinID = Old->getBuiltinID()) { // The user has declared a builtin function with an incompatible // signature. if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) { // The function the user is redeclaring is a library-defined // function like 'malloc' or 'printf'. Warn about the // redeclaration, then pretend that we don't know about this // library built-in. Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New; Diag(Old->getLocation(), diag::note_previous_builtin_declaration) << Old << Old->getType(); New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin); Old->setInvalidDecl(); return false; } PrevDiag = diag::note_previous_builtin_declaration; } Diag(New->getLocation(), diag::err_conflicting_types) << New->getDeclName(); Diag(Old->getLocation(), 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 form 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) { // Merge the attributes mergeDeclAttributes(New, Old); // Merge the storage class. if (Old->getStorageClass() != SC_Extern && Old->getStorageClass() != SC_None) New->setStorageClass(Old->getStorageClass()); // Merge "pure" flag. if (Old->isPure()) New->setPure(); // 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) mergeParamDeclAttributes(New->getParamDecl(i), Old->getParamDecl(i), Context); if (getLangOpts().CPlusPlus) return MergeCXXFunctionDecl(New, Old, S); return false; } void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, ObjCMethodDecl *oldMethod) { // We don't want to merge unavailable and deprecated attributes // except from interface to implementation. bool mergeDeprecation = isa(newMethod->getDeclContext()); // Merge the attributes. mergeDeclAttributes(newMethod, oldMethod, mergeDeprecation); // Merge attributes from the parameters. ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(); for (ObjCMethodDecl::param_iterator ni = newMethod->param_begin(), ne = newMethod->param_end(); ni != ne; ++ni, ++oi) mergeParamDeclAttributes(*ni, *oi, Context); CheckObjCMethodOverride(newMethod, oldMethod, true); } /// 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) { if (New->isInvalidDecl() || Old->isInvalidDecl()) return; QualType MergedT; if (getLangOpts().CPlusPlus) { AutoType *AT = New->getType()->getContainedAutoType(); if (AT && !AT->isDeduced()) { // 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()->isIncompleteArrayType() && New->getType()->isArrayType()) { CanQual OldArray = Context.getCanonicalType(Old->getType())->getAs(); CanQual NewArray = Context.getCanonicalType(New->getType())->getAs(); if (OldArray->getElementType() == NewArray->getElementType()) MergedT = New->getType(); } else if (Old->getType()->isArrayType() && New->getType()->isIncompleteArrayType()) { CanQual OldArray = Context.getCanonicalType(Old->getType())->getAs(); CanQual NewArray = Context.getCanonicalType(New->getType())->getAs(); if (OldArray->getElementType() == NewArray->getElementType()) MergedT = Old->getType(); } else if (New->getType()->isObjCObjectPointerType() && Old->getType()->isObjCObjectPointerType()) { MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); } } else { MergedT = Context.mergeTypes(New->getType(), Old->getType()); } if (MergedT.isNull()) { Diag(New->getLocation(), diag::err_redefinition_different_type) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } New->setType(MergedT); } /// 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; // Verify the old decl was also a variable. VarDecl *Old = 0; if (!Previous.isSingleResult() || !(Old = dyn_cast(Previous.getFoundDecl()))) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); Diag(Previous.getRepresentativeDecl()->getLocation(), diag::note_previous_definition); 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->getAttr() && Old->getStorageClass() == SC_None && !Old->getAttr()) { Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); // Remove weak_import attribute on new declaration. New->dropAttr(); } // Merge the types. MergeVarDeclTypes(New, Old); if (New->isInvalidDecl()) return; // C99 6.2.2p4: Check if we have a static decl followed by a non-static. if (New->getStorageClass() == SC_Static && (Old->getStorageClass() == SC_None || Old->hasExternalStorage())) { Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); 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->getStorageClass() != SC_Static && Old->getStorageClass() == SC_Static) { Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } // Check if extern is followed by non-extern and vice-versa. if (New->hasExternalStorage() && !Old->hasLinkage() && Old->isLocalVarDecl()) { Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } if (Old->hasExternalStorage() && !New->hasLinkage() && New->isLocalVarDecl()) { Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); 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(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } if (New->isThreadSpecified() && !Old->isThreadSpecified()) { Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); } else if (!New->isThreadSpecified() && Old->isThreadSpecified()) { Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); } // C++ doesn't have tentative definitions, so go right ahead and check here. const VarDecl *Def; if (getLangOpts().CPlusPlus && New->isThisDeclarationADefinition() == VarDecl::Definition && (Def = Old->getDefinition())) { Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(Def->getLocation(), diag::note_previous_definition); New->setInvalidDecl(); return; } // c99 6.2.2 P4. // For an identifier declared with the storage-class specifier extern in a // scope in which a prior declaration of that identifier is visible, 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. // FIXME. revisit this code. if (New->hasExternalStorage() && Old->getLinkage() == InternalLinkage && New->getDeclContext() == Old->getDeclContext()) New->setStorageClass(Old->getStorageClass()); // Keep a chain of previous declarations. New->setPreviousDeclaration(Old); // Inherit access appropriately. New->setAccess(Old->getAccess()); } /// 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) { return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg(*this, 0, 0)); } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. It also accopts template /// parameters to cope with template friend declarations. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, MultiTemplateParamsArg TemplateParams) { Decl *TagD = 0; TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || DS.getTypeSpecType() == DeclSpec::TST_struct || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { TagD = DS.getRepAsDecl(); if (!TagD) // We probably had an error return 0; // 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) { 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.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) << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3); else Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators); // Don't emit warnings after this error. return TagD; } 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 0; return ActOnFriendTypeDecl(S, DS, TemplateParams); } // Track whether we warned about the fact that there aren't any // declarators. bool emittedWarning = false; if (RecordDecl *Record = dyn_cast_or_null(Tag)) { if (!Record->getDeclName() && Record->isCompleteDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOpts().CPlusPlus || Record->getDeclContext()->isRecord()) return BuildAnonymousStructOrUnion(S, DS, AS, Record); Diag(DS.getLocStart(), diag::ext_no_declarators) << DS.getSourceRange(); emittedWarning = true; } } // Check for Microsoft C extension: anonymous struct. if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus && CurContext->isRecord() && DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { // Handle 2 kinds of anonymous struct: // struct STRUCT; // and // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct. RecordDecl *Record = dyn_cast_or_null(Tag); if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) || (DS.getTypeSpecType() == DeclSpec::TST_typename && DS.getRepAsType().get()->isStructureType())) { Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct) << DS.getSourceRange(); return BuildMicrosoftCAnonymousStruct(S, DS, Record); } } 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()) { Diag(Enum->getLocation(), diag::ext_no_declarators) << DS.getSourceRange(); emittedWarning = true; } // Skip all the checks below if we have a type error. if (DS.getTypeSpecType() == DeclSpec::TST_error) return TagD; if (!DS.isMissingDeclaratorOk()) { // Warn about typedefs of enums without names, since this is an // extension in both Microsoft and GNU. if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef && Tag && isa(Tag)) { Diag(DS.getLocStart(), diag::ext_typedef_without_a_name) << DS.getSourceRange(); return Tag; } Diag(DS.getLocStart(), diag::ext_no_declarators) << DS.getSourceRange(); emittedWarning = true; } // We're going to complain about a bunch of spurious specifiers; // only do this if we're declaring a tag, because otherwise we // should be getting diag::ext_no_declarators. if (emittedWarning || (TagD && TagD->isInvalidDecl())) return TagD; // 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 (!DS.isExternInLinkageSpec()) Diag(DS.getStorageClassSpecLoc(), diag::warn_standalone_specifier) << DeclSpec::getSpecifierName(scs); if (DS.isThreadSpecified()) Diag(DS.getThreadSpecLoc(), diag::warn_standalone_specifier) << "__thread"; if (DS.getTypeQualifiers()) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "const"; if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "volatile"; // Restrict is covered above. } if (DS.isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::warn_standalone_specifier) << "inline"; if (DS.isVirtualSpecified()) Diag(DS.getVirtualSpecLoc(), diag::warn_standalone_specifier) << "virtual"; if (DS.isExplicitSpecified()) Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit"; if (DS.isModulePrivateSpecified() && Tag && Tag->getDeclContext()->isFunctionOrMethod()) Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class) << Tag->getTagKind() << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc()); // 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_union || TypeSpecType == DeclSpec::TST_enum) { AttributeList* attrs = DS.getAttributes().getList(); while (attrs) { Diag(attrs->getScopeLoc(), diag::warn_declspec_attribute_ignored) << attrs->getName() << (TypeSpecType == DeclSpec::TST_class ? 0 : TypeSpecType == DeclSpec::TST_struct ? 1 : TypeSpecType == DeclSpec::TST_union ? 2 : 3); attrs = attrs->getNext(); } } } 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, unsigned diagnostic) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName, Sema::ForRedeclaration); if (!SemaRef.LookupName(R, S)) return false; if (R.getAsSingle()) 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, diagnostic) << 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, SmallVector &Chaining, bool MSAnonStruct) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl : diag::err_anonymous_struct_member_redecl; bool Invalid = false; // Look every FieldDecl and IndirectFieldDecl with a name. for (RecordDecl::decl_iterator D = AnonRecord->decls_begin(), DEnd = AnonRecord->decls_end(); D != DEnd; ++D) { if ((isa(*D) || isa(*D)) && cast(*D)->getDeclName()) { ValueDecl *VD = cast(*D); if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(), VD->getLocation(), diagKind)) { // 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)) for (IndirectFieldDecl::chain_iterator PI = IF->chain_begin(), PE = IF->chain_end(); PI != PE; ++PI) Chaining.push_back(*PI); 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()); 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(DeclSpec::SCS StorageClassSpec) { switch (StorageClassSpec) { case DeclSpec::SCS_unspecified: return SC_None; case DeclSpec::SCS_extern: 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"); } /// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to /// a StorageClass. Any error reporting is up to the caller: /// illegal input values are mapped to SC_None. static StorageClass StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) { switch (StorageClassSpec) { case DeclSpec::SCS_unspecified: return SC_None; case DeclSpec::SCS_extern: return SC_Extern; case DeclSpec::SCS_static: return SC_Static; case DeclSpec::SCS_private_extern: return SC_PrivateExtern; // Illegal SCSs map to None: error reporting is up to the caller. case DeclSpec::SCS_auto: // Fall through. case DeclSpec::SCS_mutable: // Fall through. case DeclSpec::SCS_register: // Fall through. case DeclSpec::SCS_typedef: return SC_None; } llvm_unreachable("unknown storage class specifier"); } /// 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) { 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 = 0; 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); } // 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); } } // 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() << 0 << FixItHint::CreateRemoval(DS.getConstSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << 1 << FixItHint::CreateRemoval(DS.getVolatileSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << 2 << FixItHint::CreateRemoval(DS.getRestrictSpecLoc()); 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 (DeclContext::decl_iterator Mem = Record->decls_begin(), MemEnd = Record->decls_end(); Mem != MemEnd; ++Mem) { if (FieldDecl *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) << (int)Record->isUnion() << (int)(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 (RecordDecl *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) << (int)Record->isUnion(); else { // This is a nested type declaration. Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type) << (int)Record->isUnion(); Invalid = true; } } } else if (isa(*Mem)) { // Any access specifier is 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) << (int)Record->isUnion(); else { Diag((*Mem)->getLocation(), DK) << (int)Record->isUnion(); Invalid = true; } } } } if (!Record->isUnion() && !Owner->isRecord()) { Diag(Record->getLocation(), diag::err_anonymous_struct_not_member) << (int)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 = 0; if (RecordDecl *OwningClass = dyn_cast(Owner)) { Anon = FieldDecl::Create(Context, OwningClass, DS.getLocStart(), Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/0, /*Mutable=*/false, /*HasInit=*/false); Anon->setAccess(AS); if (getLangOpts().CPlusPlus) FieldCollector->Add(cast(Anon)); } else { DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); assert(SCSpec != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class VarDecl."); VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec); 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; } SCSpec = DS.getStorageClassSpecAsWritten(); VarDecl::StorageClass SCAsWritten = StorageClassSpecToVarDeclStorageClass(SCSpec); Anon = VarDecl::Create(Context, Owner, DS.getLocStart(), Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, SC, SCAsWritten); // 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, /*TypeMayContainAuto=*/false); } Anon->setImplicit(); // 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, false)) Invalid = true; // Mark this as an anonymous struct/union type. Note that we do not // do this until after we have already checked and injected the // members of this anonymous struct/union type, because otherwise // the members could be injected twice: once by DeclContext when it // builds its lookup table, and once by // InjectAnonymousStructOrUnionMembers. Record->setAnonymousStructOrUnion(true); 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) { // If there is no Record, get the record via the typedef. if (!Record) Record = DS.getRepAsType().get()->getAsStructureType()->getDecl(); // Mock up a declarator. Declarator Dc(DS, Declarator::TypeNameContext); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct"); // Create a declaration for this anonymous struct. NamedDecl* Anon = FieldDecl::Create(Context, cast(CurContext), DS.getLocStart(), DS.getLocStart(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/0, /*Mutable=*/false, /*HasInit=*/false); 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 (!RecordDef || InjectAnonymousStructOrUnionMembers(*this, S, CurContext, RecordDef, AS_none, Chain, true)) Anon->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_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(0); 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, llvm::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_decltype: case DeclSpec::TST_underlyingType: case DeclSpec::TST_atomic: { // Grab the type from the parser. TypeSourceInfo *TSI = 0; 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_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(*this)); if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() && Dcl->getDeclContext()->isFileContext()) Dcl->setTopLevelDeclInObjCContainer(); 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(); if (CXXRecordDecl *Record = dyn_cast(DC)) if (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)) Cur = Cur->getParent(); // C++ [dcl.meaning]p1: // A declarator-id shall not be qualified except for the definition // of a member function (9.3) or static data member (9.4) outside of // its class, the definition or explicit instantiation of a function // or variable member of a namespace outside of its namespace, or the // definition of an explicit specialization outside of its namespace, // or the declaration of a friend function that is a member of // another class or namespace (11.3). [...] // The user provided a superfluous scope specifier that refers back to the // class or namespaces in which the entity is already declared. // // class X { // void X::f(); // }; if (Cur->Equals(DC)) { Diag(Loc, diag::warn_member_extra_qualification) << Name << FixItHint::CreateRemoval(SS.getRange()); SS.clear(); 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 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; } Decl *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 (!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 0; } else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType)) return 0; // 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 0; bool EnteringContext = !D.getDeclSpec().isFriendSpecified(); DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext); if (!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) << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep() << D.getCXXScopeSpec().getRange(); return 0; } bool IsDependentContext = DC->isDependentContext(); if (!IsDependentContext && RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) return 0; if (isa(DC) && !cast(DC)->hasDefinition()) { Diag(D.getIdentifierLoc(), diag::err_member_def_undefined_record) << Name << DC << D.getCXXScopeSpec().getRange(); D.setInvalidType(); } else if (!D.getDeclSpec().isFriendSpecified()) { if (diagnoseQualifiedDeclaration(D.getCXXScopeSpec(), DC, Name, D.getIdentifierLoc())) { if (DC->isRecord()) return 0; 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(); } } if (DiagnoseClassNameShadow(DC, NameInfo)) // If this is a typedef, we'll end up spewing multiple diagnostics. // Just return early; it's safer. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) return 0; NamedDecl *New; TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); 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; // 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 (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) /* Do nothing*/; else if (R->isFunctionType()) { if (CurContext->isFunctionOrMethod() || D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) IsLinkageLookup = true; } else if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) IsLinkageLookup = true; else if (CurContext->getRedeclContext()->isTranslationUnit() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) IsLinkageLookup = true; if (IsLinkageLookup) Previous.clear(LookupRedeclarationWithLinkage); LookupName(Previous, S, /* CreateBuiltins = */ IsLinkageLookup); } 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(); bool AddToScope = true; if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { if (TemplateParamLists.size()) { Diag(D.getIdentifierLoc(), diag::err_template_typedef); return 0; } New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous); } else if (R->isFunctionType()) { New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous, move(TemplateParamLists), AddToScope); } else { New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, move(TemplateParamLists)); } if (New == 0) return 0; // If this has an identifier and is not an invalid redeclaration or // function template specialization, add it to the scope stack. if (New->getDeclName() && AddToScope && !(D.isRedeclaration() && New->isInvalidDecl())) PushOnScopeChains(New, S); return New; } /// TryToFixInvalidVariablyModifiedType - 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); } /// \brief Register the given locally-scoped external C declaration so /// that it can be found later for redeclarations void Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, const LookupResult &Previous, Scope *S) { assert(ND->getLexicalDeclContext()->isFunctionOrMethod() && "Decl is not a locally-scoped decl!"); // Note that we have a locally-scoped external with this name. LocallyScopedExternalDecls[ND->getDeclName()] = ND; if (!Previous.isSingleResult()) return; NamedDecl *PrevDecl = Previous.getFoundDecl(); // If there was a previous declaration of this variable, it may be // in our identifier chain. Update the identifier chain with the new // declaration. if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) { // The previous declaration was found on the identifer resolver // chain, so remove it from its scope. if (S->isDeclScope(PrevDecl)) { // Special case for redeclarations in the SAME scope. // Because this declaration is going to be added to the identifier chain // later, we should temporarily take it OFF the chain. IdResolver.RemoveDecl(ND); } else { // Find the scope for the original declaration. while (S && !S->isDeclScope(PrevDecl)) S = S->getParent(); } if (S) S->RemoveDecl(PrevDecl); } } llvm::DenseMap::iterator Sema::findLocallyScopedExternalDecl(DeclarationName Name) { if (ExternalSource) { // Load locally-scoped external decls from the external source. SmallVector Decls; ExternalSource->ReadLocallyScopedExternalDecls(Decls); for (unsigned I = 0, N = Decls.size(); I != N; ++I) { llvm::DenseMap::iterator Pos = LocallyScopedExternalDecls.find(Decls[I]->getDeclName()); if (Pos == LocallyScopedExternalDecls.end()) LocallyScopedExternalDecls[Decls[I]->getDeclName()] = Decls[I]; } } return LocallyScopedExternalDecls.find(Name); } /// \brief Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { // FIXME: We should probably indicate the identifier in question to avoid // confusion for constructs like "inline int a(), b;" if (D.getDeclSpec().isInlineSpecified()) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function); if (D.getDeclSpec().isVirtualSpecified()) Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_non_function); if (D.getDeclSpec().isExplicitSpecified()) Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_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(); } if (getLangOpts().CPlusPlus) { // Check that there are no default arguments (C++ only). CheckExtraCXXDefaultArguments(D); } DiagnoseFunctionSpecifiers(D); if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); if (D.getDeclSpec().isConstexprSpecified()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 1; if (D.getName().Kind != UnqualifiedId::IK_Identifier) { Diag(D.getName().StartLocation, diag::err_typedef_not_identifier) << D.getName().getSourceRange(); return 0; } TypedefDecl *NewTD = ParseTypedefDecl(S, D, TInfo->getType(), TInfo); if (!NewTD) return 0; // 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. QualType T = NewTD->getUnderlyingType(); if (T->isVariablyModifiedType()) { getCurFunction()->setHasBranchProtectedScope(); if (S->getFnParent() == 0) { bool SizeIsNegative; llvm::APSInt Oversized; QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, Oversized); if (!FixedTy.isNull()) { Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size); NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy)); } 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) { // 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, /*ExplicitInstantiationOrSpecialization=*/false); if (!Previous.empty()) { Redeclaration = true; MergeTypedefNameDecl(NewTD, 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); else if (II->isStr("__builtin_va_list")) Context.setBuiltinVaListType(Context.getTypedefType(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->isThreadSpecified()) { Diag(var->getLocation(), diag::err_arc_thread_ownership) << var->getType(); return true; } } return false; } NamedDecl* Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists) { QualType R = TInfo->getType(); DeclarationName Name = GetNameForDeclarator(D).getName(); // Check that there are no default arguments (C++ only). if (getLangOpts().CPlusPlus) CheckExtraCXXDefaultArguments(D); DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); assert(SCSpec != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class VarDecl."); VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec); 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; } SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); VarDecl::StorageClass SCAsWritten = StorageClassSpecToVarDeclStorageClass(SCSpec); IdentifierInfo *II = Name.getAsIdentifierInfo(); if (!II) { Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) << Name; return 0; } DiagnoseFunctionSpecifiers(D); if (!DC->isRecord() && S->getFnParent() == 0) { // C99 6.9p2: The storage-class specifiers auto and register shall not // appear in the declaration specifiers in an external declaration. if (SC == SC_Auto || SC == SC_Register) { // If this is a register variable with an asm label specified, then this // is a GNU extension. if (SC == SC_Register && D.getAsmLabel()) Diag(D.getIdentifierLoc(), diag::err_unsupported_global_register); else Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope); D.setInvalidType(); } } if (getLangOpts().OpenCL) { // Set up the special work-group-local storage class for variables in the // OpenCL __local address space. if (R.getAddressSpace() == LangAS::opencl_local) SC = SC_OpenCLWorkGroupLocal; } bool isExplicitSpecialization = false; VarDecl *NewVD; if (!getLangOpts().CPlusPlus) { NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, R, TInfo, SC, SCAsWritten); if (D.isInvalidType()) NewVD->setInvalidDecl(); } else { if (DC->isRecord() && !CurContext->isRecord()) { // This is an out-of-line definition of a static data member. if (SC == SC_Static) { Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } else if (SC == SC_None) SC = SC_Static; } 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().CPlusPlus0x ? 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. isExplicitSpecialization = false; bool Invalid = false; if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), D.getCXXScopeSpec(), TemplateParamLists.get(), TemplateParamLists.size(), /*never a friend*/ false, isExplicitSpecialization, Invalid)) { if (TemplateParams->size() > 0) { // There is no such thing as a variable template. Diag(D.getIdentifierLoc(), diag::err_template_variable) << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); return 0; } else { // 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()); } } NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, R, TInfo, SC, SCAsWritten); // 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 (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && R->getContainedAutoType()) ParsingInitForAutoVars.insert(NewVD); if (D.isInvalidType() || Invalid) NewVD->setInvalidDecl(); SetNestedNameSpecifier(NewVD, D); if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) { NewVD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), TemplateParamLists.release()); } if (D.getDeclSpec().isConstexprSpecified()) NewVD->setConstexpr(true); } // 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 (D.getDeclSpec().isThreadSpecified()) { if (NewVD->hasLocalStorage()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); else if (!Context.getTargetInfo().isTLSSupported()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_unsupported); else NewVD->setThreadSpecified(true); } if (D.getDeclSpec().isModulePrivateSpecified()) { if (isExplicitSpecialization) 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(); } // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); // 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() != 0) { switch (SC) { case SC_None: case SC_Auto: Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; break; case SC_Register: if (!Context.getTargetInfo().isValidGCCRegisterName(Label)) Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; break; case SC_Static: case SC_Extern: case SC_PrivateExtern: case SC_OpenCLWorkGroupLocal: break; } } NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context, Label)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap::iterator I = ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); if (I != ExtnameUndeclaredIdentifiers.end()) { NewVD->addAttr(I->second); ExtnameUndeclaredIdentifiers.erase(I); } } // Diagnose shadowed variables before filtering for scope. if (!D.getCXXScopeSpec().isSet()) CheckShadow(S, NewVD, Previous); // 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, DC, S, NewVD->hasLinkage(), isExplicitSpecialization); if (!getLangOpts().CPlusPlus) { D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); } else { // 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(); } D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); // This is an explicit specialization of a static data member. Check it. if (isExplicitSpecialization && !NewVD->isInvalidDecl() && CheckMemberSpecialization(NewVD, Previous)) NewVD->setInvalidDecl(); } // attributes declared post-definition are currently ignored // FIXME: This should be handled in attribute merging, not // here. if (Previous.isSingleResult()) { VarDecl *Def = dyn_cast(Previous.getFoundDecl()); if (Def && (Def = Def->getDefinition()) && Def != NewVD && D.hasAttributes()) { Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition); Diag(Def->getLocation(), diag::note_previous_definition); } } // If this is a locally-scoped extern C variable, update the map of // such variables. if (CurContext->isFunctionOrMethod() && NewVD->isExternC() && !NewVD->isInvalidDecl()) RegisterLocallyScopedExternCDecl(NewVD, Previous, S); // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this variable. if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord()) AddPushedVisibilityAttribute(NewVD); MarkUnusedFileScopedDecl(NewVD); return NewVD; } /// \brief Diagnose variable or built-in function shadowing. Implements /// -Wshadow. /// /// This method is called whenever a VarDecl is added to a "useful" /// scope. /// /// \param S the scope in which the shadowing name is being declared /// \param R the lookup of the name /// void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // Return if warning is ignored. if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, R.getNameLoc()) == DiagnosticsEngine::Ignored) return; // Don't diagnose declarations at file scope. if (D->hasGlobalStorage()) return; DeclContext *NewDC = D->getDeclContext(); // Only diagnose if we're shadowing an unambiguous field or variable. if (R.getResultKind() != LookupResult::Found) return; NamedDecl* ShadowedDecl = R.getFoundDecl(); if (!isa(ShadowedDecl) && !isa(ShadowedDecl)) return; // Fields are not shadowed by variables in C++ static methods. if (isa(ShadowedDecl)) if (CXXMethodDecl *MD = dyn_cast(NewDC)) if (MD->isStatic()) 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 (VarDecl::redecl_iterator I = shadowedVar->redecls_begin(), E = shadowedVar->redecls_end(); I != E; ++I) if (I->isFileVarDecl()) { ShadowedDecl = *I; break; } } DeclContext *OldDC = ShadowedDecl->getDeclContext(); // 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. } // Determine what kind of declaration we're shadowing. unsigned Kind; if (isa(OldDC)) { if (isa(ShadowedDecl)) Kind = 3; // field else Kind = 2; // static data member } else if (OldDC->isFileContext()) Kind = 1; // global else Kind = 0; // local DeclarationName Name = R.getLookupName(); // Emit warning and note. Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC; 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.getDiagnosticLevel(diag::warn_decl_shadow, D->getLocation()) == DiagnosticsEngine::Ignored) return; LookupResult R(*this, D->getDeclName(), D->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); LookupName(R, S); CheckShadow(S, D, R); } /// \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) { // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) return false; QualType T = NewVD->getType(); 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 (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); NewVD->setInvalidDecl(); return false; } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() && !NewVD->hasAttr()) { if (getLangOpts().getGC() != LangOptions::NonGC) Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local); else 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; QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, Oversized); if (FixedTy.isNull() && 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->getStorageClass() == SC_Static) 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 false; } if (FixedTy.isNull()) { 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 false; } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); NewVD->setType(FixedTy); } if (Previous.empty() && NewVD->isExternC()) { // Since we did not find anything by this name and we're declaring // an extern "C" variable, look for a non-visible extern "C" // declaration with the same name. llvm::DenseMap::iterator Pos = findLocallyScopedExternalDecl(NewVD->getDeclName()); if (Pos != LocallyScopedExternalDecls.end()) Previous.addDecl(Pos->second); } if (T->isVoidType() && !NewVD->hasExternalStorage()) { Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) << T; NewVD->setInvalidDecl(); return false; } if (!NewVD->hasLocalStorage() && NewVD->hasAttr()) { Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); NewVD->setInvalidDecl(); return false; } if (isVM && NewVD->hasAttr()) { Diag(NewVD->getLocation(), diag::err_block_on_vm); NewVD->setInvalidDecl(); return false; } if (NewVD->isConstexpr() && !T->isDependentType() && RequireLiteralType(NewVD->getLocation(), T, PDiag(diag::err_constexpr_var_non_literal))) { NewVD->setInvalidDecl(); return false; } if (!Previous.empty()) { MergeVarDecl(NewVD, Previous); return true; } return false; } /// \brief Data used with FindOverriddenMethod struct FindOverriddenMethodData { Sema *S; CXXMethodDecl *Method; }; /// \brief Member lookup function that determines whether a given C++ /// method overrides a method in a base class, to be used with /// CXXRecordDecl::lookupInBases(). static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *UserData) { RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); FindOverriddenMethodData *Data = reinterpret_cast(UserData); DeclarationName Name = Data->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 = Data->S->Context.getTypeDeclType(BaseRecord); CanQualType CT = Data->S->Context.getCanonicalType(T); Name = Data->S->Context.DeclarationNames.getCXXDestructorName(CT); } for (Path.Decls = BaseRecord->lookup(Name); Path.Decls.first != Path.Decls.second; ++Path.Decls.first) { NamedDecl *D = *Path.Decls.first; if (CXXMethodDecl *MD = dyn_cast(D)) { if (MD->isVirtual() && !Data->S->IsOverload(Data->Method, MD, false)) return true; } } return false; } static bool hasDelayedExceptionSpec(CXXMethodDecl *Method) { const FunctionProtoType *Proto =Method->getType()->getAs(); return Proto && Proto->getExceptionSpecType() == EST_Delayed; } /// 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 virtual methods in base classes that this method might override. CXXBasePaths Paths; FindOverriddenMethodData Data; Data.Method = MD; Data.S = this; bool AddedAny = false; if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) { for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(), E = Paths.found_decls_end(); I != E; ++I) { if (CXXMethodDecl *OldMD = dyn_cast(*I)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); if (!CheckOverridingFunctionReturnType(MD, OldMD) && (hasDelayedExceptionSpec(MD) || !CheckOverridingFunctionExceptionSpec(MD, OldMD)) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { AddedAny = true; } } } } 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; }; } 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(CXXRecordDecl *Parent) : ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {} virtual bool ValidateCandidate(const TypoCorrection &candidate) { if (candidate.getEditDistance() == 0) return false; if (CXXMethodDecl *MD = candidate.getCorrectionDeclAs()) { CXXRecordDecl *Parent = MD->getParent(); return Parent && Parent->getCanonicalDecl() == ExpectedParent; } return !ExpectedParent; } private: CXXRecordDecl *ExpectedParent; }; } /// \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) { NamedDecl *Result = NULL; DeclarationName Name = NewFD->getDeclName(); DeclContext *NewDC = NewFD->getDeclContext(); LookupResult Prev(SemaRef, Name, NewFD->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); llvm::SmallVector MismatchedParams; llvm::SmallVector, 1> NearMatches; TypoCorrection Correction; bool isFriendDecl = (SemaRef.getLangOpts().CPlusPlus && ExtraArgs.D.getDeclSpec().isFriendSpecified()); unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend : diag::err_member_def_does_not_match; NewFD->setInvalidDecl(); SemaRef.LookupQualifiedName(Prev, NewDC); assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); CXXMethodDecl *MD = dyn_cast(NewFD); DifferentNameValidatorCCC Validator(MD ? MD->getParent() : 0); 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(), 0, 0, Validator, NewDC))) { // Trap errors. Sema::SFINAETrap Trap(SemaRef); // 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 && hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) { Previous.addDecl(FD); } } bool wasRedeclaration = ExtraArgs.D.isRedeclaration(); // TODO: Refactor ActOnFunctionDeclarator so that we can call only the // pieces need to verify the typo-corrected C++ declaraction 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()) { // Pretend the typo correction never occurred ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(), ExtraArgs.D.getIdentifierLoc()); ExtraArgs.D.setRedeclaration(wasRedeclaration); Previous.clear(); Previous.setLookupName(Name); Result = NULL; } else { for (LookupResult::iterator Func = Previous.begin(), FuncEnd = Previous.end(); Func != FuncEnd; ++Func) { if (FunctionDecl *FD = dyn_cast(*Func)) NearMatches.push_back(std::make_pair(FD, 0)); } } if (NearMatches.empty()) { // Ignore the correction if it didn't yield any close FunctionDecl matches Correction = TypoCorrection(); } else { DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest : diag::err_member_def_does_not_match_suggest; } } if (Correction) SemaRef.Diag(NewFD->getLocation(), DiagMsg) << Name << NewDC << Correction.getQuoted(SemaRef.getLangOpts()) << FixItHint::CreateReplacement( NewFD->getLocation(), Correction.getAsString(SemaRef.getLangOpts())); else SemaRef.Diag(NewFD->getLocation(), DiagMsg) << Name << NewDC << NewFD->getLocation(); bool NewFDisConst = false; if (CXXMethodDecl *NewMD = dyn_cast(NewFD)) NewFDisConst = NewMD->getTypeQualifiers() & Qualifiers::Const; for (llvm::SmallVector, 1>::iterator NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end(); NearMatch != NearMatchEnd; ++NearMatch) { FunctionDecl *FD = NearMatch->first; bool FDisConst = false; if (CXXMethodDecl *MD = dyn_cast(FD)) FDisConst = MD->getTypeQualifiers() & Qualifiers::Const; if (unsigned Idx = NearMatch->second) { ParmVarDecl *FDParam = FD->getParamDecl(Idx-1); SourceLocation Loc = FDParam->getTypeSpecStartLoc(); if (Loc.isInvalid()) Loc = FD->getLocation(); SemaRef.Diag(Loc, diag::note_member_def_close_param_match) << Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType(); } else if (Correction) { SemaRef.Diag(FD->getLocation(), diag::note_previous_decl) << Correction.getQuoted(SemaRef.getLangOpts()); } else if (FDisConst != NewFDisConst) { SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match) << NewFDisConst << FD->getSourceRange().getEnd(); } else SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_match); } return Result; } static FunctionDecl::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.setInvalidType(); break; case DeclSpec::SCS_unspecified: break; case DeclSpec::SCS_extern: 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, FunctionDecl::StorageClass SC, bool &IsVirtualOkay) { DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); FunctionDecl *NewFD = 0; bool isInline = D.getDeclSpec().isInlineSpecified(); DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); FunctionDecl::StorageClass SCAsWritten = StorageClassSpecToFunctionDeclStorageClass(SCSpec); 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 reference // to a type name (which eventually refers to a function type). bool HasPrototype = (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || (!isa(R.getTypePtr()) && R->isFunctionProtoType()); NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), NameInfo, R, TInfo, SC, SCAsWritten, isInline, HasPrototype); if (D.isInvalidType()) NewFD->setInvalidDecl(); // Set the lexical context. NewFD->setLexicalDeclContext(SemaRef.CurContext); 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()->getResultType(), 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().CPlusPlus0x && !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, SCAsWritten, isInline, /*hasPrototype=*/true, isConstexpr); } } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { if (!DC->isRecord()) { SemaRef.Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member); return 0; } 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 (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 0; } bool isStatic = SC == SC_Static; // [class.free]p1: // Any allocation function for a class T is a static member // (even if not explicitly declared static). if (Name.getCXXOverloadedOperator() == OO_New || Name.getCXXOverloadedOperator() == OO_Array_New) isStatic = true; // [class.free]p6 Any deallocation function for a class X is a static member // (even if not explicitly declared static). if (Name.getCXXOverloadedOperator() == OO_Delete || Name.getCXXOverloadedOperator() == OO_Array_Delete) isStatic = true; IsVirtualOkay = !isStatic; // This is a C++ method declaration. return CXXMethodDecl::Create(SemaRef.Context, cast(DC), D.getLocStart(), NameInfo, R, TInfo, isStatic, SCAsWritten, isInline, isConstexpr, SourceLocation()); } else { // 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, SCAsWritten, isInline, true/*HasPrototype*/, isConstexpr); } } 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(); FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D); if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); // Do not allow returning a objc interface by-value. if (R->getAs()->getResultType()->isObjCObjectType()) { Diag(D.getIdentifierLoc(), diag::err_object_cannot_be_passed_returned_by_value) << 0 << R->getAs()->getResultType() << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); QualType T = R->getAs()->getResultType(); T = Context.getObjCObjectPointerType(T); if (const FunctionProtoType *FPT = dyn_cast(R)) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); R = Context.getFunctionType(T, FPT->arg_type_begin(), FPT->getNumArgs(), EPI); } else if (isa(R)) R = Context.getFunctionNoProtoType(T); } bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = 0; bool isExplicitSpecialization = false; bool isFunctionTemplateSpecialization = false; bool isDependentClassScopeExplicitSpecialization = false; bool isVirtualOkay = false; FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC, isVirtualOkay); if (!NewFD) return 0; if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer()) NewFD->setTopLevelDeclInObjCContainer(); if (getLangOpts().CPlusPlus) { bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); 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(); } SetNestedNameSpecifier(NewFD, D); isExplicitSpecialization = false; isFunctionTemplateSpecialization = false; if (D.isInvalidType()) NewFD->setInvalidDecl(); // Set the lexical context. If the declarator 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); // 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(), TemplateParamLists.get(), TemplateParamLists.size(), isFriend, isExplicitSpecialization, Invalid)) { if (TemplateParams->size() > 0) { // This is a function template // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) return 0; // A destructor cannot be a template. if (Name.getNameKind() == DeclarationName::CXXDestructorName) { Diag(NewFD->getLocation(), diag::err_destructor_template); return 0; } // 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.size() - 1, TemplateParamLists.release()); } } else { // This is a function template specialization. isFunctionTemplateSpecialization = true; // For source fidelity, store all the template param lists. NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), TemplateParamLists.release()); // 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 = PP.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.size(), TemplateParamLists.release()); } if (Invalid) { NewFD->setInvalidDecl(); if (FunctionTemplate) FunctionTemplate->setInvalidDecl(); } // If we see "T var();" at block scope, where T is a class type, it is // probably an attempt to initialize a variable, not a function declaration. // We don't catch this case earlier, since there is no ambiguity here. if (!FunctionTemplate && D.getFunctionDefinitionKind() == FDK_Declaration && CurContext->isFunctionOrMethod() && D.getNumTypeObjects() == 1 && D.isFunctionDeclarator() && D.getDeclSpec().getStorageClassSpecAsWritten() == DeclSpec::SCS_unspecified) { QualType T = R->getAs()->getResultType(); DeclaratorChunk &C = D.getTypeObject(0); if (!T->isVoidType() && C.Fun.NumArgs == 0 && !C.Fun.isVariadic && !C.Fun.TrailingReturnType && C.Fun.getExceptionSpecType() == EST_None) { SourceRange ParenRange(C.Loc, C.EndLoc); Diag(C.Loc, diag::warn_empty_parens_are_function_decl) << ParenRange; // If the declaration looks like: // T var1, // f(); // and name lookup finds a function named 'f', then the ',' was // probably intended to be a ';'. if (!D.isFirstDeclarator() && D.getIdentifier()) { FullSourceLoc Comma(D.getCommaLoc(), SourceMgr); FullSourceLoc Name(D.getIdentifierLoc(), SourceMgr); if (Comma.getFileID() != Name.getFileID() || Comma.getSpellingLineNumber() != Name.getSpellingLineNumber()) { LookupResult Result(*this, D.getIdentifier(), SourceLocation(), LookupOrdinaryName); if (LookupName(Result, S)) Diag(D.getCommaLoc(), diag::note_empty_parens_function_call) << FixItHint::CreateReplacement(D.getCommaLoc(), ";") << NewFD; } } const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); // Empty parens mean value-initialization, and no parens mean default // initialization. These are equivalent if the default constructor is // user-provided, or if zero-initialization is a no-op. if (RD && RD->hasDefinition() && (RD->isEmpty() || RD->hasUserProvidedDefaultConstructor())) Diag(C.Loc, diag::note_empty_parens_default_ctor) << FixItHint::CreateRemoval(ParenRange); else if (const char *Init = getFixItZeroInitializerForType(T)) Diag(C.Loc, diag::note_empty_parens_zero_initialize) << FixItHint::CreateReplacement(ParenRange, Init); else if (LangOpts.CPlusPlus0x) Diag(C.Loc, diag::note_empty_parens_zero_initialize) << FixItHint::CreateReplacement(ParenRange, "{}"); } } // 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); } } // 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()) { 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++0x [dcl.constexpr]p2: constexpr functions and constexpr constructors // are implicitly inline. NewFD->setImplicitlyInline(); // C++0x [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 __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) { // For now, claim that the objects have no previous declaration. if (FunctionTemplate) { FunctionTemplate->setObjectOfFriendDecl(false); FunctionTemplate->setAccess(AS_public); } NewFD->setObjectOfFriendDecl(false); NewFD->setAccess(AS_public); } // If a function is defined as defaulted or deleted, mark it as such now. 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()); } } // Filter out previous declarations that don't match the scope. FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), isExplicitSpecialization || 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())); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap::iterator I = ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier()); if (I != ExtnameUndeclaredIdentifiers.end()) { NewFD->addAttr(I->second); ExtnameUndeclaredIdentifiers.erase(I); } } // Copy the parameter declarations from the declarator D to the function // declaration NewFD, if they are available. First scavenge them into Params. SmallVector Params; if (D.isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // 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 (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && FTI.ArgInfo[0].Param && cast(FTI.ArgInfo[0].Param)->getType()->isVoidType()) { // Empty arg list, don't push any params. ParmVarDecl *Param = cast(FTI.ArgInfo[0].Param); // In C++, the empty parameter-type-list must be spelled "void"; a // typedef of void is not permitted. if (getLangOpts().CPlusPlus && Param->getType().getUnqualifiedType() != Context.VoidTy) { bool IsTypeAlias = false; if (const TypedefType *TT = Param->getType()->getAs()) IsTypeAlias = isa(TT->getDecl()); else if (const TemplateSpecializationType *TST = Param->getType()->getAs()) IsTypeAlias = TST->isTypeAlias(); Diag(Param->getLocation(), diag::err_param_typedef_of_void) << IsTypeAlias; } } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) { for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast(FTI.ArgInfo[i].Param); assert(Param->getDeclContext() != NewFD && "Was set before ?"); Param->setDeclContext(NewFD); Params.push_back(Param); if (Param->isInvalidDecl()) NewFD->setInvalidDecl(); } } } 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 (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), AE = FT->arg_type_end(); AI != AE; ++AI) { 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); // Find all anonymous symbols defined during the declaration of this function // and add to NewFD. This lets us track decls such 'enum Y' in: // // void f(enum Y {AA} x) {} // // which would otherwise incorrectly end up in the translation unit scope. NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope); DeclsInPrototypeScope.clear(); // Process the non-inheritable attributes on this declaration. ProcessDeclAttributes(S, NewFD, D, /*NonInheritable=*/true, /*Inheritable=*/false); // Functions returning a variably modified type violate C99 6.7.5.2p2 // because all functions have linkage. if (!NewFD->isInvalidDecl() && NewFD->getResultType()->isVariablyModifiedType()) { Diag(NewFD->getLocation(), diag::err_vm_func_decl); NewFD->setInvalidDecl(); } if (!getLangOpts().CPlusPlus) { // Perform semantic checking on the function declaration. bool isExplicitSpecialization=false; if (!NewFD->isInvalidDecl()) { if (NewFD->isMain()) CheckMain(NewFD, D.getDeclSpec()); D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization)); } assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); } else { // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; TemplateArgumentListInfo TemplateArgs; if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { TemplateIdAnnotation *TemplateId = D.getName().TemplateId; TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, TemplateArgs); TemplateArgsPtr.release(); 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 if (!isFunctionTemplateSpecialization && !D.getDeclSpec().isFriendSpecified()) { // We have encountered something that the user meant to be a // specialization (because it has explicitly-specified template // arguments) but that was not introduced with a "template<>" (or had // too few of them). Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) << FixItHint::CreateInsertion( D.getDeclSpec().getLocStart(), "template<> "); isFunctionTemplateSpecialization = true; } else { // "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()); } // 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.getArgumentArray(), TemplateArgs.size(), 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 : 0), Previous)) NewFD->setInvalidDecl(); // C++ [dcl.stc]p1: // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) if (SC != SC_None) { if (SC != NewFD->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 (isExplicitSpecialization && isa(NewFD)) { if (CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); } // Perform semantic checking on the function declaration. if (!isDependentClassScopeExplicitSpecialization) { if (NewFD->isInvalidDecl()) { // If this is a class member, mark the class invalid immediately. // This avoids some consistency errors later. if (CXXMethodDecl* methodDecl = dyn_cast(NewFD)) methodDecl->getParent()->setInvalidDecl(); } else { if (NewFD->isMain()) CheckMain(NewFD, D.getDeclSpec()); D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization)); } } assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); NamedDecl *PrincipalDecl = (FunctionTemplate ? cast(FunctionTemplate) : NewFD); if (isFriend && D.isRedeclaration()) { AccessSpecifier Access = AS_public; if (!NewFD->isInvalidDecl()) Access = NewFD->getPreviousDecl()->getAccess(); NewFD->setAccess(Access); if (FunctionTemplate) FunctionTemplate->setAccess(Access); PrincipalDecl->setObjectOfFriendDecl(true); } 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() : 0, 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)) { 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)) { AddToScope = ExtraArgs.AddToScope; return Result; } } } else if (!D.isFunctionDefinition() && D.getCXXScopeSpec().isSet() && !isFriend && !isFunctionTemplateSpecialization && !isExplicitSpecialization) { // An out-of-line member function declaration must also be a // definition (C++ [dcl.meaning]p1). // 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(); } } // Handle attributes. We need to have merged decls when handling attributes // (for example to check for conflicts, etc). // FIXME: This needs to happen before we merge declarations. Then, // let attribute merging cope with attribute conflicts. ProcessDeclAttributes(S, NewFD, D, /*NonInheritable=*/false, /*Inheritable=*/true); // attributes declared post-definition are currently ignored // FIXME: This should happen during attribute merging if (D.isRedeclaration() && Previous.isSingleResult()) { const FunctionDecl *Def; FunctionDecl *PrevFD = dyn_cast(Previous.getFoundDecl()); if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) { Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition); Diag(Def->getLocation(), diag::note_previous_definition); } } 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; EPI.Variadic = true; EPI.ExtInfo = FT->getExtInfo(); QualType R = Context.getFunctionType(FT->getResultType(), 0, 0, 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 (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord()) AddPushedVisibilityAttribute(NewFD); // If there's a #pragma clang arc_cf_code_audited in scope, consider // marking the function. AddCFAuditedAttribute(NewFD); // If this is a locally-scoped extern C function, update the // map of such names. if (CurContext->isFunctionOrMethod() && NewFD->isExternC() && !NewFD->isInvalidDecl()) RegisterLocallyScopedExternCDecl(NewFD, Previous, S); // Set this FunctionDecl's range up to the right paren. NewFD->setRangeEnd(D.getSourceRange().getEnd()); if (getLangOpts().CPlusPlus) { if (FunctionTemplate) { if (NewFD->isInvalidDecl()) FunctionTemplate->setInvalidDecl(); return FunctionTemplate; } } MarkUnusedFileScopedDecl(NewFD); if (getLangOpts().CUDA) if (IdentifierInfo *II = NewFD->getIdentifier()) if (!NewFD->isInvalidDecl() && NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (II->isStr("cudaConfigureCall")) { if (!R->getAs()->getResultType()->isScalarType()) Diag(NewFD->getLocation(), diag::err_config_scalar_return); Context.setcudaConfigureCallDecl(NewFD); } } // 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)); CurContext->addDecl(NewSpec); AddToScope = false; } return NewFD; } /// \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 IsExplicitSpecialiation whether this new function declaration is /// an explicit specialization of 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 IsExplicitSpecialization) { assert(!NewFD->getResultType()->isVariablyModifiedType() && "Variably modified return types are not handled here"); // Check for a previous declaration of this name. if (Previous.empty() && NewFD->isExternC()) { // Since we did not find anything by this name and we're declaring // an extern "C" function, look for a non-visible extern "C" // declaration with the same name. llvm::DenseMap::iterator Pos = findLocallyScopedExternalDecl(NewFD->getDeclName()); if (Pos != LocallyScopedExternalDecls.end()) Previous.addDecl(Pos->second); } bool Redeclaration = false; // 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. NamedDecl *OldDecl = 0; if (!AllowOverloadingOfFunction(Previous, Context)) { Redeclaration = true; OldDecl = Previous.getFoundDecl(); } 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 = 0; if (Redeclaration) OverloadedDecl = OldDecl; else if (!Previous.empty()) OverloadedDecl = Previous.getRepresentativeDecl(); if (OverloadedDecl) Diag(OverloadedDecl->getLocation(), diag::note_attribute_overloadable_prev_overload); NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(), Context)); } } if (Redeclaration) { // NewFD and OldDecl represent declarations that need to be // merged. if (MergeFunctionDecl(NewFD, OldDecl, S)) { 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 (IsExplicitSpecialization && NewTemplateDecl->getInstantiatedFromMemberTemplate()) { NewTemplateDecl->setMemberSpecialization(); assert(OldTemplateDecl->isMemberSpecialization()); } } else { if (isa(NewFD)) // Set access for out-of-line definitions NewFD->setAccess(OldDecl->getAccess()); NewFD->setPreviousDeclaration(cast(OldDecl)); } } } // 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); } // Find any virtual functions that this function overrides. if (CXXMethodDecl *Method = dyn_cast(NewFD)) { if (!Method->isFunctionTemplateSpecialization() && !Method->getDescribedFunctionTemplate()) { if (AddOverriddenMethods(Method->getParent(), Method)) { // If the function was marked as "static", we have a problem. if (NewFD->getStorageClass() == SC_Static) { Diag(NewFD->getLocation(), diag::err_static_overrides_virtual) << NewFD->getDeclName(); for (CXXMethodDecl::method_iterator Overridden = Method->begin_overridden_methods(), OverriddenEnd = Method->end_overridden_methods(); Overridden != OverriddenEnd; ++Overridden) { Diag((*Overridden)->getLocation(), diag::note_overridden_virtual_function); } } } } 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; QualType T = Context.GetBuiltinType(BuiltinID, Error); if (!T.isNull() && !Context.hasSameType(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. if (NewFD->isExternC()) { QualType R = NewFD->getResultType(); if (!R.isPODType(Context) && !R->isVoidType()) Diag( NewFD->getLocation(), diag::warn_return_value_udt ) << NewFD << R; } } 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. // C99 6.7.4p4: In a hosted environment, the inline function specifier // shall not appear in a declaration of main. // static main is not an error under C99, but we should warn about it. 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 (FD->isConstexpr()) { Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main) << FixItHint::CreateRemoval(DS.getConstexprSpecLoc()); FD->setConstexpr(false); } QualType T = FD->getType(); assert(T->isFunctionType() && "function decl is not of function type"); const FunctionType* FT = T->castAs(); // All the standards say that main() should should return 'int'. if (Context.hasSameUnqualifiedType(FT->getResultType(), Context.IntTy)) { // 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. FD->setHasImplicitReturnZero(true); // 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. } else if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) { Diag(FD->getTypeSpecStartLoc(), diag::ext_main_returns_nonint); // Otherwise, this is just a flat-out error. } else { Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint); FD->setInvalidDecl(true); } // Treat protoless main() as nullary. if (isa(FT)) return; const FunctionProtoType* FTP = cast(FT); unsigned nparams = FTP->getNumArgs(); assert(FD->getNumParams() == nparams); bool HasExtraParameters = (nparams > 3); // 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->getArgType(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()) && (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_main_template_decl); 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.) if (Init->isConstantInitializer(Context, false)) return false; Diag(Init->getExprLoc(), diag::err_init_element_not_constant) << Init->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; public: typedef EvaluatedExprVisitor Inherited; SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context), S(S), OrigDecl(OrigDecl) { isPODType = false; isRecordType = false; if (ValueDecl *VD = dyn_cast(OrigDecl)) { isPODType = VD->getType().isPODType(S.Context); isRecordType = VD->getType()->isRecordType(); } } void VisitExpr(Expr *E) { if (isa(*E)) return; if (isRecordType) { Expr *expr = E; if (MemberExpr *ME = dyn_cast(E)) { ValueDecl *VD = ME->getMemberDecl(); if (isa(VD) || isa(VD)) return; expr = ME->getBase(); } if (DeclRefExpr *DRE = dyn_cast(expr)) { HandleDeclRefExpr(DRE); return; } } Inherited::VisitExpr(E); } void VisitMemberExpr(MemberExpr *E) { if (E->getType()->canDecayToPointerType()) return; ValueDecl *VD = E->getMemberDecl(); if (isa(VD) || isa(VD)) if (DeclRefExpr *DRE = dyn_cast(E->getBase()->IgnoreParenImpCasts())) { HandleDeclRefExpr(DRE); return; } Inherited::VisitMemberExpr(E); } void VisitImplicitCastExpr(ImplicitCastExpr *E) { if ((!isRecordType &&E->getCastKind() == CK_LValueToRValue) || (isRecordType && E->getCastKind() == CK_NoOp)) { Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts(); if (MemberExpr *ME = dyn_cast(SubExpr)) SubExpr = ME->getBase()->IgnoreParenImpCasts(); if (DeclRefExpr *DRE = dyn_cast(SubExpr)) { HandleDeclRefExpr(DRE); return; } } Inherited::VisitImplicitCastExpr(E); } void VisitUnaryOperator(UnaryOperator *E) { // For POD record types, addresses of its own members are well-defined. if (isRecordType && isPODType) return; Inherited::VisitUnaryOperator(E); } void HandleDeclRefExpr(DeclRefExpr *DRE) { Decl* ReferenceDecl = DRE->getDecl(); if (OrigDecl != ReferenceDecl) return; LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName, Sema::NotForRedeclaration); S.DiagRuntimeBehavior(DRE->getLocStart(), DRE, S.PDiag(diag::warn_uninit_self_reference_in_init) << Result.getLookupName() << OrigDecl->getLocation() << DRE->getSourceRange()); } }; } /// CheckSelfReference - Warns if OrigDecl is used in expression E. void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) { SelfReferenceChecker(*this, OrigDecl).VisitExpr(E); } /// 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, bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore // the initializer. if (RealDecl == 0 || RealDecl->isInvalidDecl()) return; if (CXXMethodDecl *Method = dyn_cast(RealDecl)) { // With declarators parsed the way they are, the parser cannot // distinguish between a normal initializer and a pure-specifier. // Thus this grotesque test. IntegerLiteral *IL; if ((IL = dyn_cast(Init)) && IL->getValue() == 0 && Context.getCanonicalType(IL->getType()) == Context.IntTy) CheckPureMethod(Method, Init->getSourceRange()); else { 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; } // Check for self-references within variable initializers. // Variables declared within a function/method body are handled // by a dataflow analysis. if (!VDecl->hasLocalStorage() && !VDecl->isStaticLocal()) CheckSelfReference(RealDecl, Init); ParenListExpr *CXXDirectInit = dyn_cast(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { Expr *DeduceInit = Init; // Initializer could be a C++ direct-initializer. Deduction only works if it // contains exactly one expression. if (CXXDirectInit) { if (CXXDirectInit->getNumExprs() == 0) { // It isn't possible to write this directly, but it is possible to // end up in this situation with "auto x(some_pack...);" Diag(CXXDirectInit->getLocStart(), diag::err_auto_var_init_no_expression) << VDecl->getDeclName() << VDecl->getType() << VDecl->getSourceRange(); RealDecl->setInvalidDecl(); return; } else if (CXXDirectInit->getNumExprs() > 1) { Diag(CXXDirectInit->getExpr(1)->getLocStart(), diag::err_auto_var_init_multiple_expressions) << VDecl->getDeclName() << VDecl->getType() << VDecl->getSourceRange(); RealDecl->setInvalidDecl(); return; } else { DeduceInit = CXXDirectInit->getExpr(0); } } TypeSourceInfo *DeducedType = 0; if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) == DAR_Failed) DiagnoseAutoDeductionFailure(VDecl, DeduceInit); if (!DeducedType) { RealDecl->setInvalidDecl(); return; } VDecl->setTypeSourceInfo(DeducedType); VDecl->setType(DeducedType->getType()); VDecl->ClearLinkageCache(); // 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()) MergeVarDeclTypes(VDecl, Old); } 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(); } const VarDecl *Def; if ((Def = VDecl->getDefinition()) && Def != VDecl) { Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); Diag(Def->getLocation(), diag::note_previous_definition); VDecl->setInvalidDecl(); return; } const VarDecl* PrevInit = 0; 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->getAnyInitializer(PrevInit)) { Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); Diag(PrevInit->getLocation(), diag::note_previous_definition); 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->getStorageClass() == SC_OpenCLWorkGroupLocal) { 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; // Top-level message sends default to 'id' when we're in a debugger // and we are assigning it to a variable of 'id' type. if (getLangOpts().DebuggerCastResultToId && DclT->isObjCIdType()) if (Init->getType() == Context.UnknownAnyTy && isa(Init)) { ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType()); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } Init = Result.take(); } // Perform the initialization. if (!VDecl->isInvalidDecl()) { InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); InitializationKind Kind = DirectInit ? CXXDirectInit ? InitializationKind::CreateDirect(VDecl->getLocation(), Init->getLocStart(), Init->getLocEnd()) : InitializationKind::CreateDirectList( VDecl->getLocation()) : InitializationKind::CreateCopy(VDecl->getLocation(), Init->getLocStart()); Expr **Args = &Init; unsigned NumArgs = 1; if (CXXDirectInit) { Args = CXXDirectInit->getExprs(); NumArgs = CXXDirectInit->getNumExprs(); } InitializationSequence InitSeq(*this, Entity, Kind, Args, NumArgs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(*this, Args,NumArgs), &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } Init = Result.takeAs(); } // 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); // Check any implicit conversions within the expression. CheckImplicitConversions(Init, VDecl->getLocation()); if (!VDecl->isInvalidDecl()) checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); Init = MaybeCreateExprWithCleanups(Init); // Attach the initializer to the decl. VDecl->setInit(Init); if (VDecl->isLocalVarDecl()) { // 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. // C++ does not have this restriction. if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl() && VDecl->getStorageClass() == SC_Static) CheckForConstantInitializer(Init, DclT); } else if (VDecl->isStaticDataMember() && 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 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 initalizer-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().CPlusPlus0x && 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 Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type) << DclT << Init->getSourceRange(); if (getLangOpts().CPlusPlus0x) Diag(VDecl->getLocation(), diag::note_in_class_initializer_float_type_constexpr) << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); 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().CPlusPlus0x && DclT->isLiteralType()) { 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()) { if (VDecl->getStorageClassAsWritten() == SC_Extern && (!getLangOpts().CPlusPlus || !Context.getBaseElementType(VDecl->getType()).isConstQualified())) 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; // 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 an 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, bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore it. if (RealDecl == 0) return; if (VarDecl *Var = dyn_cast(RealDecl)) { QualType Type = Var->getType(); // C++11 [dcl.spec.auto]p3 if (TypeMayContainAuto && Type->getContainedAutoType()) { Diag(Var->getLocation(), diag::err_auto_var_requires_init) << Var->getDeclName() << Type; Var->setInvalidDecl(); 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()) { if (Var->isStaticDataMember()) Diag(Var->getLocation(), diag::err_constexpr_static_mem_var_requires_init) << Var->getDeclName(); else Diag(Var->getLocation(), diag::err_invalid_constexpr_var_decl); 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->getLinkage() && !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(); 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->getPreviousDecl() == 0) 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 (RequireCompleteType(Var->getLocation(), Context.getBaseElementType(Type), diag::err_typecheck_decl_incomplete_type)) { Var->setInvalidDecl(); 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, 0, 0); ExprResult Init = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(*this, 0, 0)); 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) { 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->getStorageClassAsWritten()) { 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; case SC_OpenCLWorkGroupLocal: llvm_unreachable("Unexpected storage class"); } if (VD->isConstexpr()) Error = 5; if (Error != -1) { Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class) << VD->getDeclName() << Error; D->setInvalidDecl(); } } void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; // In ARC, don't allow jumps past the implicit initialization of a // local retaining variable. if (getLangOpts().ObjCAutoRefCount && 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; } } // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) return; QualType baseType = Context.getBaseElementType(var->getType()); if (baseType->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. QualType type = var->getType(); if (type->isStructureOrClassType()) { SourceLocation poi = var->getLocation(); Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi); ExprResult result = PerformCopyInitialization( InitializedEntity::InitializeBlock(poi, type, false), poi, Owned(varRef)); if (!result.isInvalid()) { result = MaybeCreateExprWithCleanups(result); Expr *init = result.takeAs(); Context.setBlockVarCopyInits(var, init); } } } Expr *Init = var->getInit(); bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal(); if (!var->getDeclContext()->isDependentContext() && Init) { if (IsGlobal && !var->isConstexpr() && getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor, var->getLocation()) != DiagnosticsEngine::Ignored && !Init->isConstantInitializer(Context, baseType->isReferenceType())) Diag(var->getLocation(), diag::warn_global_constructor) << Init->getSourceRange(); if (var->isConstexpr()) { llvm::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(); } } // Require the destructor. if (const RecordType *recordType = baseType->getAs()) FinalizeVarWithDestructor(var, recordType); } /// 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); } Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, Decl **Group, unsigned NumDecls) { SmallVector Decls; if (DS.isTypeSpecOwned()) Decls.push_back(DS.getRepAsDecl()); for (unsigned i = 0; i != NumDecls; ++i) if (Decl *D = Group[i]) Decls.push_back(D); return BuildDeclaratorGroup(Decls.data(), Decls.size(), DS.getTypeSpecType() == DeclSpec::TST_auto); } /// BuildDeclaratorGroup - convert a list of declarations into a declaration /// group, performing any necessary semantic checking. Sema::DeclGroupPtrTy Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls, bool TypeMayContainAuto) { // C++0x [dcl.spec.auto]p7: // If the type deduced for the template parameter U is not the same in each // deduction, the program is ill-formed. // FIXME: When initializer-list support is added, a distinction is needed // between the deduced type U and the deduced type which 'auto' stands for. // auto a = 0, b = { 1, 2, 3 }; // is legal because the deduced type U is 'int' in both cases. if (TypeMayContainAuto && NumDecls > 1) { QualType Deduced; CanQualType DeducedCanon; VarDecl *DeducedDecl = 0; for (unsigned i = 0; i != NumDecls; ++i) { if (VarDecl *D = dyn_cast(Group[i])) { AutoType *AT = D->getType()->getContainedAutoType(); // Don't reissue diagnostics when instantiating a template. if (AT && D->isInvalidDecl()) break; if (AT && AT->isDeduced()) { QualType U = AT->getDeducedType(); CanQualType UCanon = Context.getCanonicalType(U); if (Deduced.isNull()) { Deduced = U; DeducedCanon = UCanon; DeducedDecl = D; } else if (DeducedCanon != UCanon) { Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_auto_different_deductions) << Deduced << DeducedDecl->getDeclName() << U << D->getDeclName() << DeducedDecl->getInit()->getSourceRange() << D->getInit()->getSourceRange(); D->setInvalidDecl(); break; } } } } } return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, NumDecls)); } /// 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'. VarDecl::StorageClass StorageClass = SC_None; VarDecl::StorageClass StorageClassAsWritten = SC_None; if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { StorageClass = SC_Register; StorageClassAsWritten = SC_Register; } else if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_auto) { StorageClass = SC_Auto; StorageClassAsWritten = SC_Auto; } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); D.getMutableDeclSpec().ClearStorageClassSpecs(); } if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); if (D.getDeclSpec().isConstexprSpecified()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 0; DiagnoseFunctionSpecifiers(D); 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 = 0; if (D.hasName()) { II = D.getIdentifier(); if (!II) { Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name) << GetNameForDeclarator(D).getName().getAsString(); 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 = 0; } 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 = 0; D.SetIdentifier(0, 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, StorageClass, StorageClassAsWritten); 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, 0, T, Context.getTrivialTypeSourceInfo(T, Loc), SC_None, SC_None, 0); Param->setImplicit(); return Param; } void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param, ParmVarDecl * const *ParamEnd) { // Don't diagnose unused-parameter errors in template instantiations; we // will already have done so in the template itself. if (!ActiveTemplateInstantiations.empty()) return; for (; Param != ParamEnd; ++Param) { if (!(*Param)->isReferenced() && (*Param)->getDeclName() && !(*Param)->hasAttr()) { Diag((*Param)->getLocation(), diag::warn_unused_parameter) << (*Param)->getDeclName(); } } } void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, ParmVarDecl * const *ParamEnd, 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 (; Param != ParamEnd; ++Param) { QualType T = (*Param)->getType(); if (T->isDependentType() || !T.isPODType(Context)) continue; unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); if (Size > LangOpts.NumLargeByValueCopy) Diag((*Param)->getLocation(), diag::warn_parameter_size) << (*Param)->getDeclName() << Size; } } ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, SourceLocation NameLoc, IdentifierInfo *Name, QualType T, TypeSourceInfo *TSInfo, VarDecl::StorageClass StorageClass, VarDecl::StorageClass StorageClassAsWritten) { // 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, StorageClass, StorageClassAsWritten, 0); // 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()) { Diag(NameLoc, diag::err_object_cannot_be_passed_returned_by_value) << 1 << T << FixItHint::CreateInsertion(NameLoc, "*"); 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) { 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.NumArgs; i != 0; /* decrement in loop */) { --i; if (FTI.ArgInfo[i].Param == 0) { SmallString<256> Code; llvm::raw_svector_ostream(Code) << " int " << FTI.ArgInfo[i].Ident->getName() << ";\n"; Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared) << FTI.ArgInfo[i].Ident << FixItHint::CreateInsertion(LocAfterDecls, Code.str()); // 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.ArgInfo[i].IdentLoc, PrevSpec, DiagID); Declarator ParamD(DS, Declarator::KNRTypeListContext); ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc); FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD); } } } } Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { assert(getCurFunctionDecl() == 0 && "Function parsing confused"); assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); D.setFunctionDefinitionKind(FDK_Definition); Decl *DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg(*this)); return ActOnStartOfFunctionDef(FnBodyScope, DP); } static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) { // 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; 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->getDeclContext()->isFunctionOrMethod()) continue; MissingPrototype = !Prev->getType()->isFunctionProtoType(); break; } return MissingPrototype; } void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) { // Don't complain if we're in GNU89 mode and the previous definition // was an extern inline function. const FunctionDecl *Definition; if (FD->isDefined(Definition) && !canRedefineFunction(Definition, getLangOpts())) { 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); } } Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // Clear the last template instantiation error context. LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); if (!D) return D; FunctionDecl *FD = 0; if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) FD = FunTmpl->getTemplatedDecl(); else FD = cast(D); // Enter a new function scope PushFunctionScope(); // See if this is a redefinition. if (!FD->isLateTemplateParsed()) CheckForFunctionRedefinition(FD); // Builtin functions cannot be defined. if (unsigned BuiltinID = FD->getBuiltinID()) { if (!Context.BuiltinInfo.isPredefinedLibFunction(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->getResultType(); if (!ResultType->isDependentType() && !ResultType->isVoidType() && !FD->isInvalidDecl() && RequireCompleteType(FD->getLocation(), ResultType, diag::err_func_def_incomplete_result)) FD->setInvalidDecl(); // 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. if (ShouldWarnAboutMissingPrototype(FD)) Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; if (FnBodyScope) PushDeclContext(FnBodyScope, FD); // Check the validity of our function parameters CheckParmsForFunctionDef(FD->param_begin(), FD->param_end(), /*CheckParameterNames=*/true); // Introduce our parameters into the function scope for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); Param->setOwningFunction(FD); // If this has an identifier, add it to the scope stack. if (Param->getIdentifier() && FnBodyScope) { CheckShadow(FnBodyScope, Param); PushOnScopeChains(Param, FnBodyScope); } } // If we had any tags defined in the function prototype, // introduce them into the function scope. if (FnBodyScope) { for (llvm::ArrayRef::iterator I = FD->getDeclsInPrototypeScope().begin(), E = FD->getDeclsInPrototypeScope().end(); I != E; ++I) { NamedDecl *D = *I; // Some of these decls (like enums) may have been pinned to the translation unit // for lack of a real context earlier. If so, remove from the translation unit // and reattach to the current context. if (D->getLexicalDeclContext() == Context.getTranslationUnitDecl()) { // Is the decl actually in the context? for (DeclContext::decl_iterator DI = Context.getTranslationUnitDecl()->decls_begin(), DE = Context.getTranslationUnitDecl()->decls_end(); DI != DE; ++DI) { if (*DI == D) { Context.getTranslationUnitDecl()->removeDecl(D); break; } } // Either way, reassign the lexical decl context to our FunctionDecl. D->setLexicalDeclContext(CurContext); } // If the decl has a non-null name, make accessible in the current scope. if (!D->getName().empty()) PushOnScopeChains(D, FnBodyScope, /*AddToContext=*/false); // Similarly, dive into enums and fish their constants out, making them // accessible in this scope. if (EnumDecl *ED = dyn_cast(D)) { for (EnumDecl::enumerator_iterator EI = ED->enumerator_begin(), EE = ED->enumerator_end(); EI != EE; ++EI) PushOnScopeChains(*EI, FnBodyScope, /*AddToContext=*/false); } } } // Ensure that the function's exception specification is instantiated. if (const FunctionProtoType *FPT = FD->getType()->getAs()) ResolveExceptionSpec(D->getLocation(), FPT); // Checking attributes of current function definition // dllimport attribute. DLLImportAttr *DA = FD->getAttr(); if (DA && (!FD->getAttr())) { // dllimport attribute cannot be directly applied to definition. // Microsoft accepts dllimport for functions defined within class scope. if (!DA->isInherited() && !(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) { Diag(FD->getLocation(), diag::err_attribute_can_be_applied_only_to_symbol_declaration) << "dllimport"; FD->setInvalidDecl(); return FD; } // Visual C++ appears to not think this is an issue, so only issue // a warning when Microsoft extensions are disabled. if (!LangOpts.MicrosoftExt) { // If a symbol previously declared dllimport is later defined, the // attribute is ignored in subsequent references, and a warning is // emitted. Diag(FD->getLocation(), diag::warn_redeclaration_without_attribute_prev_attribute_ignored) << FD->getName() << "dllimport"; } } return FD; } /// \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 function has the same NRVO candidate, that candidate is /// the NRVO variable. /// /// FIXME: Employ a smarter algorithm that accounts for multiple return /// statements and the lifetimes of the NRVO candidates. We should be able to /// find a maximal set of NRVO variables. void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { ReturnStmt **Returns = Scope->Returns.data(); const VarDecl *NRVOCandidate = 0; for (unsigned I = 0, E = Scope->Returns.size(); I != E; ++I) { if (!Returns[I]->getNRVOCandidate()) return; if (!NRVOCandidate) NRVOCandidate = Returns[I]->getNRVOCandidate(); else if (NRVOCandidate != Returns[I]->getNRVOCandidate()) return; } if (NRVOCandidate) const_cast(NRVOCandidate)->setNRVOVariable(true); } Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) { return ActOnFinishFunctionBody(D, move(BodyArg), false); } Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation) { FunctionDecl *FD = 0; FunctionTemplateDecl *FunTmpl = dyn_cast_or_null(dcl); if (FunTmpl) FD = FunTmpl->getTemplatedDecl(); else FD = dyn_cast_or_null(dcl); sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = 0; if (FD) { FD->setBody(Body); // 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()) Diag(FD->getLocation(), diag::warn_pure_function_definition); if (!FD->isInvalidDecl()) { DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(), FD->getResultType(), FD); // If this is a constructor, we need a vtable. if (CXXConstructorDecl *Constructor = dyn_cast(FD)) MarkVTableUsed(FD->getLocation(), Constructor->getParent()); computeNRVO(Body, getCurFunction()); } 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 (Body) MD->setEndLoc(Body->getLocEnd()); if (!MD->isInvalidDecl()) { DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(), MD->getResultType(), MD); if (Body) computeNRVO(Body, getCurFunction()); } if (ObjCShouldCallSuperDealloc) { Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc); ObjCShouldCallSuperDealloc = false; } if (ObjCShouldCallSuperFinalize) { Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize); ObjCShouldCallSuperFinalize = false; } } else { return 0; } assert(!ObjCShouldCallSuperDealloc && "This should only be set for " "ObjC methods, which should have been handled in the block above."); assert(!ObjCShouldCallSuperFinalize && "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) { // 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() && !dcl->isInvalidDecl() && !hasAnyUnrecoverableErrorsInThisFunction()) 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 (PP.getDiagnostics().hasErrorOccurred() || PP.getDiagnostics().getSuppressAllDiagnostics()) { DiscardCleanupsInEvaluationContext(); } else if (!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(); assert(ExprCleanupObjects.empty() && "Leftover temporaries in function"); assert(!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. llvm::DenseMap::iterator Pos = findLocallyScopedExternalDecl(&II); if (Pos != LocallyScopedExternalDecls.end()) { Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second; Diag(Pos->second->getLocation(), diag::note_previous_declaration); return Pos->second; } // 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; DeclFilterCCC Validator; if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc), LookupOrdinaryName, S, 0, Validator))) { std::string CorrectedStr = Corrected.getAsString(getLangOpts()); std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts()); FunctionDecl *Func = Corrected.getCorrectionDeclAs(); Diag(Loc, diag::note_function_suggestion) << CorrectedQuotedStr << FixItHint::CreateReplacement(Loc, CorrectedStr); if (Func->getLocation().isValid() && !II.getName().startswith("__builtin_")) Diag(Func->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; } } // 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); (void)Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); Declarator D(DS, Declarator::BlockContext); D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0, 0, 0, true, SourceLocation(), SourceLocation(), SourceLocation(), SourceLocation(), EST_None, SourceLocation(), - 0, 0, 0, 0, 0, Loc, Loc, D), + 0, 0, 0, 0, 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 = dyn_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->getAttr()) { 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(::new (Context) FormatAttr(FD->getLocation(), Context, fmt, FormatIdx+1, HasVAListArg ? 0 : FormatIdx+2)); } } if (Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx, HasVAListArg)) { if (!FD->getAttr()) FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context, "scanf", FormatIdx+1, HasVAListArg ? 0 : FormatIdx+2)); } // 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->getAttr()) FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) && !FD->getAttr()) FD->addAttr(::new (Context) ReturnsTwiceAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr()) FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr()) FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } 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->getAttr()) FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context, "printf", 2, Name->isStr("vasprintf") ? 0 : 3)); } } 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_union: case TST_class: { TagDecl *tagFromDeclSpec = cast(D.getDeclSpec().getRepAsDecl()); // Do nothing if the tag is not anonymous or already has an // associated typedef (from an earlier typedef in this decl group). if (tagFromDeclSpec->getIdentifier()) break; if (tagFromDeclSpec->getTypedefNameForAnonDecl()) break; // 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(T, Context.getTagDeclType(tagFromDeclSpec))) break; // Otherwise, set this is the anon-decl typedef for the tag. tagFromDeclSpec->setTypedefNameForAnonDecl(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() || T->isIntegralType(Context)) 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, 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_use); return true; } if (IsFixed && Prev->isFixed()) { if (!EnumUnderlyingTy->isDependentType() && !Prev->getIntegerType()->isDependentType() && !Context.hasSameUnqualifiedType(EnumUnderlyingTy, Prev->getIntegerType())) { Diag(EnumLoc, diag::err_enum_redeclare_type_mismatch) << EnumUnderlyingTy << Prev->getIntegerType(); Diag(Prev->getLocation(), diag::note_previous_use); return true; } } else if (IsFixed != Prev->isFixed()) { Diag(EnumLoc, diag::err_enum_redeclare_fixed_mismatch) << Prev->isFixed(); Diag(Prev->getLocation(), diag::note_previous_use); return true; } return false; } /// \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 || (NewTag != TTK_Class && NewTag != TTK_Struct)) if (OldTag == NewTag) return true; if ((OldTag == TTK_Struct || OldTag == TTK_Class) && (NewTag == TTK_Struct || NewTag == TTK_Class)) { // Warn about the struct/class tag mismatch. bool isTemplate = false; if (const CXXRecordDecl *Record = dyn_cast(Previous)) isTemplate = Record->getDescribedClassTemplate(); if (!ActiveTemplateInstantiations.empty()) { // 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) << (NewTag == TTK_Class) << isTemplate << &Name; 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 (TagDecl::redecl_iterator I(Previous->redecls_begin()), E(Previous->redecls_end()); I != E; ++I) { if (I->getTagKind() != NewTag) { if (!previousMismatch) { previousMismatch = true; Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) << (NewTag == TTK_Class) << isTemplate << &Name; } Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) << (NewTag == TTK_Class) << FixItHint::CreateReplacement(I->getInnerLocStart(), NewTag == TTK_Class? "class" : "struct"); } } 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) << (NewTag == TTK_Class) << isTemplate << &Name; Diag(Redecl->getLocation(), diag::note_previous_use); // If there is a previous defintion, suggest a fix-it. if (Previous->getDefinition()) { Diag(NewTagLoc, diag::note_struct_class_suggestion) << (Redecl->getTagKind() == TTK_Class) << FixItHint::CreateReplacement(SourceRange(NewTagLoc), Redecl->getTagKind() == TTK_Class? "class" : "struct"); } return true; } return false; } /// ActOnTag - 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. 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) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != 0 || 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 explicit specializations more carefully. bool isExplicitSpecialization = 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, TemplateParameterLists.get(), TemplateParameterLists.size(), TUK == TUK_Friend, isExplicitSpecialization, Invalid)) { 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 0; OwnedDecl = false; DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attr, TemplateParams, AS, ModulePrivateLoc, TemplateParameterLists.size() - 1, (TemplateParameterList**) TemplateParameterLists.release()); return Result.get(); } else { // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) << TypeWithKeyword::getTagTypeKindName(Kind) << Name; isExplicitSpecialization = 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; 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 = 0; 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 (getLangOpts().MicrosoftMode) // Microsoft enums are always of int type. EnumUnderlying = Context.IntTy.getTypePtr(); } DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; bool isStdBadAlloc = 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 = 0; 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 0; } } else { DC = computeDeclContext(SS, true); if (!DC) { Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec) << SS.getRange(); return 0; } } if (RequireCompleteDeclContext(SS, DC)) return 0; SearchDC = DC; // Look-up name inside 'foo::'. LookupQualifiedName(Previous, DC); if (Previous.isAmbiguous()) return 0; 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 0; } // A tag 'foo::bar' must already exist. Diag(NameLoc, diag::err_not_tag_in_scope) << Kind << Name << DC << SS.getRange(); Name = 0; Invalid = true; goto CreateNewDecl; } } else if (Name) { // 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); 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() != SearchDC) F.erase(); } F.done(); } // Note: there used to be some attempt at recovery here. if (Previous.isAmbiguous()) return 0; 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(); } } else if (S->isFunctionPrototypeScope()) { // If this is an enum declaration in function prototype scope, set its // initial context to the translation unit. // FIXME: [citation needed] SearchDC = Context.getTranslationUnitDecl(); } 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()) && Name->isStr("bad_alloc")) { // This is a declaration of or a reference to "std::bad_alloc". isStdBadAlloc = true; if (Previous.empty() && StdBadAlloc) { // 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. Previous.addDecl(getStdBadAlloc()); } } // 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, while (!SearchDC->isFileContext() && !SearchDC->isFunctionOrMethod()) SearchDC = SearchDC->getParent(); // Find the scope where we'll be declaring the tag. while (S->isClassScope() || (getLangOpts().CPlusPlus && S->isFunctionPrototypeScope()) || ((S->getFlags() & Scope::DeclScope) == 0) || (S->getEntity() && ((DeclContext *)S->getEntity())->isTransparentContext())) S = S->getParent(); } 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. if (getLangOpts().CPlusPlus) { Previous.setRedeclarationKind(ForRedeclaration); LookupQualifiedName(Previous, SearchDC); } } if (!Previous.empty()) { NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl(); // 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 (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(PrevDecl, SearchDC, S, isExplicitSpecialization)) { // 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 = 0; 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(); 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, PrevEnum)) return TUK == TUK_Declaration ? PrevTagDecl : 0; } if (!Invalid) { // If this is a use, just return the declaration we found. // FIXME: In the future, return a variant or some other clue // for the consumer of this Decl to know it doesn't own it. // For our current ASTs this shouldn't be a problem, but will // need to be changed with DeclGroups. if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() || getLangOpts().MicrosoftExt)) || TUK == TUK_Friend) return PrevTagDecl; // Diagnose attempts to redefine a tag. if (TUK == TUK_Definition) { if (TagDecl *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 (isExplicitSpecialization) { if (CXXRecordDecl *RD = dyn_cast(Def)) IsExplicitSpecializationAfterInstantiation = RD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization; else if (EnumDecl *ED = dyn_cast(Def)) IsExplicitSpecializationAfterInstantiation = ED->getTemplateSpecializationKind() != TSK_ExplicitSpecialization; } 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; Diag(Def->getLocation(), diag::note_previous_definition); // If this is a redefinition, recover by making this // struct be anonymous, which will make any later // references get the previous definition. Name = 0; Previous.clear(); Invalid = true; } } else { // If the type is currently being defined, complain // about a nested redefinition. const TagType *Tag = cast(Context.getTagDeclType(PrevTagDecl)); if (Tag->isBeingDefined()) { Diag(NameLoc, diag::err_nested_redefinition) << Name; Diag(PrevTagDecl->getLocation(), diag::note_previous_definition); Name = 0; Previous.clear(); Invalid = true; } } // Okay, this is definition of a previously declared or referenced // tag PrevDecl. We're going to create a new Decl for it. } } // 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()) { unsigned Kind = 0; if (isa(PrevDecl)) Kind = 1; else if (isa(PrevDecl)) Kind = 2; else if (isa(PrevDecl)) Kind = 3; Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind; Diag(PrevDecl->getLocation(), diag::note_declared_at); Invalid = true; // Otherwise, only diagnose if the declaration is in scope. } else if (!isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) { // do nothing // Diagnose implicit declarations introduced by elaborated types. } else if (TUK == TUK_Reference || TUK == TUK_Friend) { unsigned Kind = 0; if (isa(PrevDecl)) Kind = 1; else if (isa(PrevDecl)) Kind = 2; else if (isa(PrevDecl)) Kind = 3; Diag(NameLoc, diag::err_tag_reference_conflict) << Kind; 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; Diag(PrevDecl->getLocation(), diag::note_previous_definition); Name = 0; 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 = 0; 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 this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; if (getLangOpts().CPlusPlus0x && 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().MicrosoftMode) 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)); } // 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 (!isExplicitSpecialization && (TUK == TUK_Definition || TUK == TUK_Declaration) && diagnoseQualifiedDeclaration(SS, DC, OrigName, NameLoc)) Invalid = true; New->setQualifierInfo(SS.getWithLocInContext(Context)); if (TemplateParameterLists.size() > 0) { New->setTemplateParameterListsInfo(Context, TemplateParameterLists.size(), (TemplateParameterList**) TemplateParameterLists.release()); } } 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). AddAlignmentAttributesForRecord(RD); AddMsStructLayoutForRecord(RD); } if (ModulePrivateLoc.isValid()) { if (isExplicitSpecialization) 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 (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) Invalid = true; if (Invalid) New->setInvalidDecl(); if (Attr) ProcessDeclAttributeList(S, New, Attr); // 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. if (Name && S->isFunctionPrototypeScope() && !getLangOpts().CPlusPlus) Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); // 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(/* PreviouslyDeclared = */ !Previous.empty() || getLangOpts().MicrosoftExt); // Set the access specifier. if (!Invalid && SearchDC->isRecord()) SetMemberAccessSpecifier(New, PrevDecl, AS); if (TUK == TUK_Definition) New->startDefinition(); // 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 we were in function prototype scope (and not in C++ mode), add this // tag to the list of decls to inject into the function definition scope. if (S->isFunctionPrototypeScope() && !getLangOpts().CPlusPlus && InFunctionDeclarator && Name) DeclsInPrototypeScope.push_back(New); OwnedDecl = true; return New; } void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast(TagD); // Enter the tag context. PushDeclContext(S, 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, SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); CXXRecordDecl *Record = cast(TagD); FieldCollector->StartClass(); if (!Record->getIdentifier()) return; if (FinalLoc.isValid()) Record->addAttr(new (Context) FinalAttr(FinalLoc, Context)); // 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=*/0, /*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, SourceLocation RBraceLoc) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast(TagD); Tag->setRBraceLoc(RBraceLoc); // 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(); // Notify the consumer that we've defined a tag. 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 = 0; } 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, 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 Owned(BitWidth); llvm::APSInt Value; ExprResult ICE = VerifyIntegerConstantExpression(BitWidth, &Value); if (ICE.isInvalid()) return ICE; BitWidth = ICE.take(); 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 TypeSize = Context.getTypeSize(FieldTy); if (Value.getZExtValue() > TypeSize) { if (!getLangOpts().CPlusPlus) { if (FieldName) return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size) << FieldName << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size) << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; } if (FieldName) Diag(FieldLoc, diag::warn_bitfield_width_exceeds_type_size) << FieldName << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; else Diag(FieldLoc, diag::warn_anon_bitfield_width_exceeds_type_size) << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; } } return Owned(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), /*HasInit=*/false, 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, bool HasInit, AccessSpecifier AS) { 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); } } DiagnoseFunctionSpecifiers(D); if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); if (D.getDeclSpec().isConstexprSpecified()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 2; // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = 0; 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 = 0; } if (PrevDecl && !isDeclInScope(PrevDecl, Record, S)) PrevDecl = 0; bool Mutable = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); SourceLocation TSSL = D.getLocStart(); FieldDecl *NewFD = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit, 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, bool HasInit, 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; } } } // 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; QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, Oversized); if (!FixedTy.isNull()) { Diag(Loc, diag::warn_illegal_constant_array_size); T = FixedTy; } 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 this is declared as a bit-field, check the bit-field. if (!InvalidDecl && BitWidth) { BitWidth = VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth).take(); if (!BitWidth) { InvalidDecl = true; BitWidth = 0; ZeroWidth = false; } } // Check that 'mutable' is consistent with the type of the declaration. if (!InvalidDecl && Mutable) { unsigned DiagID = 0; if (T->isReferenceType()) DiagID = 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); Mutable = false; InvalidDecl = true; } } FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, BitWidth, Mutable, HasInit); 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. if (EltTy->isReferenceType()) { Diag(NewFD->getLocation(), diag::err_union_member_of_reference_type) << NewFD->getDeclName() << EltTy; NewFD->setInvalidDecl(); } } } // FIXME: We need to pass in the attributes given an AST // representation, not a parser representation. if (D) // FIXME: What to pass instead of TUScope? ProcessDeclAttributes(TUScope, NewFD, *D); // 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()) return true; 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; if (!RDecl->hasTrivialCopyConstructor()) member = CXXCopyConstructor; else if (!RDecl->hasTrivialDefaultConstructor()) member = CXXDefaultConstructor; else if (!RDecl->hasTrivialCopyAssignment()) member = CXXCopyAssignment; else if (!RDecl->hasTrivialDestructor()) member = CXXDestructor; if (member != CXXInvalid) { if (!getLangOpts().CPlusPlus0x && 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(new (Context) UnavailableAttr(Loc, Context, "this system field has retaining ownership")); return false; } } Diag(FD->getLocation(), getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member : diag::err_illegal_union_or_anon_struct_member) << (int)FD->getParent()->isUnion() << FD->getDeclName() << member; DiagnoseNontrivial(RT, member); return !getLangOpts().CPlusPlus0x; } } } return false; } /// If the given constructor is user-provided, produce a diagnostic explaining /// that it makes the class non-trivial. static bool DiagnoseNontrivialUserProvidedCtor(Sema &S, QualType QT, CXXConstructorDecl *CD, Sema::CXXSpecialMember CSM) { if (!CD->isUserProvided()) return false; SourceLocation CtorLoc = CD->getLocation(); S.Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << CSM; return true; } /// DiagnoseNontrivial - Given that a class has a non-trivial /// special member, figure out why. void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { QualType QT(T, 0U); CXXRecordDecl* RD = cast(T->getDecl()); // Check whether the member was user-declared. switch (member) { case CXXInvalid: break; case CXXDefaultConstructor: if (RD->hasUserDeclaredConstructor()) { typedef CXXRecordDecl::ctor_iterator ctor_iter; for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI) if (DiagnoseNontrivialUserProvidedCtor(*this, QT, *CI, member)) return; // No user-provided constructors; look for constructor templates. typedef CXXRecordDecl::specific_decl_iterator tmpl_iter; for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); TI != TE; ++TI) { CXXConstructorDecl *CD = dyn_cast(TI->getTemplatedDecl()); if (CD && DiagnoseNontrivialUserProvidedCtor(*this, QT, CD, member)) return; } } break; case CXXCopyConstructor: if (RD->hasUserDeclaredCopyConstructor()) { SourceLocation CtorLoc = RD->getCopyConstructor(0)->getLocation(); Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; } break; case CXXMoveConstructor: if (RD->hasUserDeclaredMoveConstructor()) { SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation(); Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; } break; case CXXCopyAssignment: if (RD->hasUserDeclaredCopyAssignment()) { // FIXME: this should use the location of the copy // assignment, not the type. SourceLocation TyLoc = RD->getLocStart(); Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member; return; } break; case CXXMoveAssignment: if (RD->hasUserDeclaredMoveAssignment()) { SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation(); Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member; return; } break; case CXXDestructor: if (RD->hasUserDeclaredDestructor()) { SourceLocation DtorLoc = LookupDestructor(RD)->getLocation(); Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; } break; } typedef CXXRecordDecl::base_class_iterator base_iter; // Virtual bases and members inhibit trivial copying/construction, // but not trivial destruction. if (member != CXXDestructor) { // Check for virtual bases. vbases includes indirect virtual bases, // so we just iterate through the direct bases. for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) if (bi->isVirtual()) { SourceLocation BaseLoc = bi->getLocStart(); Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1; return; } // Check for virtual methods. typedef CXXRecordDecl::method_iterator meth_iter; for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; ++mi) { if (mi->isVirtual()) { SourceLocation MLoc = mi->getLocStart(); Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0; return; } } } bool (CXXRecordDecl::*hasTrivial)() const; switch (member) { case CXXDefaultConstructor: hasTrivial = &CXXRecordDecl::hasTrivialDefaultConstructor; break; case CXXCopyConstructor: hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break; case CXXCopyAssignment: hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break; case CXXDestructor: hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break; default: llvm_unreachable("unexpected special member"); } // Check for nontrivial bases (and recurse). for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) { const RecordType *BaseRT = bi->getType()->getAs(); assert(BaseRT && "Don't know how to handle dependent bases"); CXXRecordDecl *BaseRecTy = cast(BaseRT->getDecl()); if (!(BaseRecTy->*hasTrivial)()) { SourceLocation BaseLoc = bi->getLocStart(); Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member; DiagnoseNontrivial(BaseRT, member); return; } } // Check for nontrivial members (and recurse). typedef RecordDecl::field_iterator field_iter; for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe; ++fi) { QualType EltTy = Context.getBaseElementType((*fi)->getType()); if (const RecordType *EltRT = EltTy->getAs()) { CXXRecordDecl* EltRD = cast(EltRT->getDecl()); if (!(EltRD->*hasTrivial)()) { SourceLocation FLoc = (*fi)->getLocation(); Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member; DiagnoseNontrivial(EltRT, member); return; } } if (EltTy->isObjCLifetimeType()) { switch (EltTy.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: break; case Qualifiers::OCL_Autoreleasing: case Qualifiers::OCL_Weak: case Qualifiers::OCL_Strong: Diag((*fi)->getLocation(), diag::note_nontrivial_objc_ownership) << QT << EltTy.getObjCLifetime(); return; } } } llvm_unreachable("found no explanation for non-trivial member"); } /// 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, BitWidth).take(); 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 0; ObjCContainerDecl *EnclosingContext; if (ObjCImplementationDecl *IMPDecl = dyn_cast(EnclosingDecl)) { if (!LangOpts.ObjCNonFragileABI2) { // 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.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) { Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); return 0; } } 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); } 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.ObjCNonFragileABI2 || 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, 0, Context.CharTy, Context.getTrivialTypeSourceInfo(Context.CharTy, DeclLoc), ObjCIvarDecl::Private, BW, true); AllIvarDecls.push_back(Ivar); } void Sema::ActOnFields(Scope* S, SourceLocation RecLoc, Decl *EnclosingDecl, llvm::ArrayRef Fields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *Attr) { assert(EnclosingDecl && "missing record or interface decl"); // If the decl this is being inserted into is invalid, then it may be a // redeclaration or some other bogus case. Don't try to add fields to it. if (EnclosingDecl->isInvalidDecl()) return; 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 (RecordDecl::decl_iterator i = Record->decls_begin(), e = Record->decls_end(); i != e; i++) { if (IndirectFieldDecl *IFD = dyn_cast(*i)) if (IFD->getDeclName()) ++NumNamedMembers; } } // Verify that all the fields are okay. SmallVector RecFields; bool ARCErrReported = false; for (llvm::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. if (getLangOpts().MicrosoftExt) { if (Record->isUnion()) Diag(FD->getLocation(), diag::ext_flexible_array_union_ms) << FD->getDeclName(); else if (Fields.size() == 1) Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_ms) << FD->getDeclName() << Record->getTagKind(); } else if (getLangOpts().CPlusPlus) { if (Record->isUnion()) Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu) << FD->getDeclName(); else if (Fields.size() == 1) Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_gnu) << FD->getDeclName() << Record->getTagKind(); } else if (!getLangOpts().C99) { if (Record->isUnion()) Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu) << FD->getDeclName(); else Diag(FD->getLocation(), diag::ext_c99_flexible_array_member) << FD->getDeclName() << Record->getTagKind(); } else if (NumNamedMembers < 1) { Diag(FD->getLocation(), diag::err_flexible_array_empty_struct) << FD->getDeclName(); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; } if (!FD->getType()->isDependentType() && !Context.getBaseElementType(FD->getType()).isPODType(Context)) { Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type) << FD->getDeclName() << FD->getType(); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; } // Okay, we have a legal flexible array member at the end of the struct. if (Record) 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 (FDTTy->getDecl()->hasFlexibleArrayMember()) { // If this is a member of a union, then entire union becomes "flexible". if (Record && Record->isUnion()) { Record->setHasFlexibleArrayMember(true); } else { // 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 (Record) Record->setHasFlexibleArrayMember(true); } } } if (Record && FDTTy->getDecl()->hasObjectMember()) Record->setHasObjectMember(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().CPlusPlus) { if (getLangOpts().ObjCAutoRefCount && Record && !ARCErrReported) { // It's an error in ARC 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(); Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime(); if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) { SourceLocation loc = FD->getLocation(); if (getSourceManager().isInSystemHeader(loc)) { if (!FD->hasAttr()) { FD->addAttr(new (Context) UnavailableAttr(loc, Context, "this system field has retaining ownership")); } } else { Diag(FD->getLocation(), diag::err_arc_objc_object_in_struct) << T->isBlockPointerType(); } ARCErrReported = 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); } } } // 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. UnresolvedSetImpl *Convs = CXXRecord->getConversionFunctions(); for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I) Convs->setAccess(I, (*I)->getAccess()); if (!CXXRecord->isDependentType()) { // Objective-C Automatic Reference Counting: // If a class has a non-static data member of Objective-C pointer // type (or array thereof), it is a non-POD type and its // default constructor (if any), copy constructor, copy assignment // operator, and destructor are non-trivial. // // This rule is also handled by CXXRecordDecl::completeDefinition(). // However, here we check whether this particular class is only // non-POD because of the presence of an Objective-C pointer member. // If so, objects of this type cannot be shared between code compiled // with instant objects and code compiled with manual retain/release. if (getLangOpts().ObjCAutoRefCount && CXXRecord->hasObjectMember() && CXXRecord->getLinkage() == ExternalLinkage) { if (CXXRecord->isPOD()) { Diag(CXXRecord->getLocation(), diag::warn_arc_non_pod_class_with_object_member) << CXXRecord; } else { // FIXME: Fix-Its would be nice here, but finding a good location // for them is going to be tricky. if (CXXRecord->hasTrivialCopyConstructor()) Diag(CXXRecord->getLocation(), diag::warn_arc_trivial_member_function_with_object_member) << CXXRecord << 0; if (CXXRecord->hasTrivialCopyAssignment()) Diag(CXXRecord->getLocation(), diag::warn_arc_trivial_member_function_with_object_member) << CXXRecord << 1; if (CXXRecord->hasTrivialDestructor()) Diag(CXXRecord->getLocation(), diag::warn_arc_trivial_member_function_with_object_member) << CXXRecord << 2; } } // Adjust user-defined destructor exception spec. if (getLangOpts().CPlusPlus0x && CXXRecord->hasUserDeclaredDestructor()) AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor()); // 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) << (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) << (NamedDecl *)M->first << OM->Method->getParent(); Record->setInvalidDecl(); } } CXXRecord->completeDefinition(&FinalOverriders); Completed = true; } } } } if (!Completed) Record->completeDefinition(); - - // Now that the record is complete, do any delayed exception spec checks - // we were missing. - while (!DelayedDestructorExceptionSpecChecks.empty()) { - const CXXDestructorDecl *Dtor = - DelayedDestructorExceptionSpecChecks.back().first; - if (Dtor->getParent() != Record) - break; - - assert(!Dtor->getParent()->isDependentType() && - "Should not ever add destructors of templates into the list."); - CheckOverridingFunctionExceptionSpec(Dtor, - DelayedDestructorExceptionSpecChecks.back().second); - DelayedDestructorExceptionSpecChecks.pop_back(); - } } 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 ObjCCategoryDecl *ClsExtDecl = IDecl->getFirstClassExtension(); ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) { if (const ObjCIvarDecl *ClsExtIvar = ClsExtDecl->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); // If there's a #pragma GCC visibility in scope, and this isn't a subclass, // set the visibility of this record. if (Record && !Record->getDeclContext()->isRecord()) AddPushedVisibilityAttribute(Record); } /// \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 = 0; if (Val) Val = DefaultLvalueConversion(Val).take(); if (Val) { if (Enum->isDependentType() || Val->isTypeDependent()) EltTy = Context.DependentTy; else { SourceLocation ExpLoc; if (getLangOpts().CPlusPlus0x && Enum->isFixed() && !getLangOpts().MicrosoftMode) { // 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 = 0; else Val = Converted.take(); } else if (!Val->isValueDependent() && !(Val = VerifyIntegerConstantExpression(Val, &EnumVal).take())) { // 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().MicrosoftMode) { Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take(); } else Diag(IdLoc, diag::err_enumerator_too_large) << EltTy; } else Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take(); } 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).take(); } 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::warn_enumerator_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); } 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 = 0; } 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)) { if (isa(PrevDecl)) Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id; else Diag(IdLoc, diag::err_redefinition) << Id; Diag(PrevDecl->getLocation(), diag::note_previous_definition); return 0; } } // 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 enumerator of every member of class T that is an enumerated // type if (CXXRecordDecl *Record = dyn_cast( TheEnumDecl->getDeclContext()->getRedeclContext())) if (Record->getIdentifier() && Record->getIdentifier() == Id) Diag(IdLoc, diag::err_member_name_of_class) << Id; EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); if (New) { // Process attributes. if (Attr) ProcessDeclAttributeList(S, New, Attr); // Register this decl in the current scope stack. New->setAccess(TheEnumDecl->getAccess()); PushOnScopeChains(New, S); } return New; } void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, Decl *EnumDeclX, Decl **Elements, unsigned NumElements, 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; i != NumElements; ++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; i != NumElements; ++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->getAttr() ? true : false; // -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; // We don't need to set BestWidth, because BestType is going to be the type // of the enumerators, but we do anyway because otherwise some compilers // warn that it might be used uninitialized. BestWidth = CharWidth; } 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::warn_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 (unsigned i = 0; i != NumElements; ++i) { EnumConstantDecl *ECD = cast_or_null(Elements[i]); 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*/ 0, 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); // If we're declaring a function, ensure this decl isn't forgotten about - // it needs to go into the function scope. if (InFunctionDeclarator) DeclsInPrototypeScope.push_back(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; } DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc, ModuleIdPath Path) { Module *Mod = PP.getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, /*IsIncludeDirective=*/false); if (!Mod) return true; llvm::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); } ImportDecl *Import = ImportDecl::Create(Context, Context.getTranslationUnitDecl(), AtLoc.isValid()? AtLoc : ImportLoc, Mod, IdentifierLocs); Context.getTranslationUnitDecl()->addDecl(Import); return Import; } void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation NameLoc, SourceLocation AliasNameLoc) { Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); AsmLabelAttr *Attr = ::new (Context) AsmLabelAttr(AliasNameLoc, Context, AliasName->getName()); if (PrevDecl) PrevDecl->addAttr(Attr); else (void)ExtnameUndeclaredIdentifiers.insert( std::pair(Name, Attr)); } void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc) { Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); if (PrevDecl) { PrevDecl->addAttr(::new (Context) WeakAttr(PragmaLoc, Context)); } else { (void)WeakUndeclaredIdentifiers.insert( std::pair (Name, WeakInfo((IdentifierInfo*)0, 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) { 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)); } AvailabilityResult Sema::getCurContextAvailability() const { const Decl *D = cast(getCurLexicalContext()); // A category implicitly has the availability of the interface. if (const ObjCCategoryDecl *CatD = dyn_cast(D)) D = CatD->getClassInterface(); return D->getAvailability(); } Index: vendor/clang/dist/lib/Sema/SemaDeclCXX.cpp =================================================================== --- vendor/clang/dist/lib/Sema/SemaDeclCXX.cpp (revision 235808) +++ vendor/clang/dist/lib/Sema/SemaDeclCXX.cpp (revision 235809) @@ -1,11362 +1,11340 @@ //===------ SemaDeclCXX.cpp - Semantic Analysis for C++ 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 C++ declarations. // //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/Scope.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CharUnits.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" #include #include using namespace clang; //===----------------------------------------------------------------------===// // CheckDefaultArgumentVisitor //===----------------------------------------------------------------------===// namespace { /// CheckDefaultArgumentVisitor - C++ [dcl.fct.default] Traverses /// the default argument of a parameter to determine whether it /// contains any ill-formed subexpressions. For example, this will /// diagnose the use of local variables or parameters within the /// default argument expression. class CheckDefaultArgumentVisitor : public StmtVisitor { Expr *DefaultArg; Sema *S; public: CheckDefaultArgumentVisitor(Expr *defarg, Sema *s) : DefaultArg(defarg), S(s) {} bool VisitExpr(Expr *Node); bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitCXXThisExpr(CXXThisExpr *ThisE); bool VisitLambdaExpr(LambdaExpr *Lambda); }; /// VisitExpr - Visit all of the children of this expression. bool CheckDefaultArgumentVisitor::VisitExpr(Expr *Node) { bool IsInvalid = false; for (Stmt::child_range I = Node->children(); I; ++I) IsInvalid |= Visit(*I); return IsInvalid; } /// VisitDeclRefExpr - Visit a reference to a declaration, to /// determine whether this declaration can be used in the default /// argument expression. bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { NamedDecl *Decl = DRE->getDecl(); if (ParmVarDecl *Param = dyn_cast(Decl)) { // C++ [dcl.fct.default]p9 // Default arguments are evaluated each time the function is // called. The order of evaluation of function arguments is // unspecified. Consequently, parameters of a function shall not // be used in default argument expressions, even if they are not // evaluated. Parameters of a function declared before a default // argument expression are in scope and can hide namespace and // class member names. return S->Diag(DRE->getLocStart(), diag::err_param_default_argument_references_param) << Param->getDeclName() << DefaultArg->getSourceRange(); } else if (VarDecl *VDecl = dyn_cast(Decl)) { // C++ [dcl.fct.default]p7 // Local variables shall not be used in default argument // expressions. if (VDecl->isLocalVarDecl()) return S->Diag(DRE->getLocStart(), diag::err_param_default_argument_references_local) << VDecl->getDeclName() << DefaultArg->getSourceRange(); } return false; } /// VisitCXXThisExpr - Visit a C++ "this" expression. bool CheckDefaultArgumentVisitor::VisitCXXThisExpr(CXXThisExpr *ThisE) { // C++ [dcl.fct.default]p8: // The keyword this shall not be used in a default argument of a // member function. return S->Diag(ThisE->getLocStart(), diag::err_param_default_argument_references_this) << ThisE->getSourceRange(); } bool CheckDefaultArgumentVisitor::VisitLambdaExpr(LambdaExpr *Lambda) { // C++11 [expr.lambda.prim]p13: // A lambda-expression appearing in a default argument shall not // implicitly or explicitly capture any entity. if (Lambda->capture_begin() == Lambda->capture_end()) return false; return S->Diag(Lambda->getLocStart(), diag::err_lambda_capture_default_arg); } } void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method) { // If we have an MSAny or unknown spec already, don't bother. if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) return; const FunctionProtoType *Proto = Method->getType()->getAs(); Proto = Self->ResolveExceptionSpec(CallLoc, Proto); if (!Proto) return; ExceptionSpecificationType EST = Proto->getExceptionSpecType(); // If this function can throw any exceptions, make a note of that. if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) { ClearExceptions(); ComputedEST = EST; return; } // FIXME: If the call to this decl is using any of its default arguments, we // need to search them for potentially-throwing calls. // If this function has a basic noexcept, it doesn't affect the outcome. if (EST == EST_BasicNoexcept) return; // If we have a throw-all spec at this point, ignore the function. if (ComputedEST == EST_None) return; // If we're still at noexcept(true) and there's a nothrow() callee, // change to that specification. if (EST == EST_DynamicNone) { if (ComputedEST == EST_BasicNoexcept) ComputedEST = EST_DynamicNone; return; } // Check out noexcept specs. if (EST == EST_ComputedNoexcept) { FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(Self->Context); assert(NR != FunctionProtoType::NR_NoNoexcept && "Must have noexcept result for EST_ComputedNoexcept."); assert(NR != FunctionProtoType::NR_Dependent && "Should not generate implicit declarations for dependent cases, " "and don't know how to handle them anyway."); // noexcept(false) -> no spec on the new function if (NR == FunctionProtoType::NR_Throw) { ClearExceptions(); ComputedEST = EST_None; } // noexcept(true) won't change anything either. return; } assert(EST == EST_Dynamic && "EST case not considered earlier."); assert(ComputedEST != EST_None && "Shouldn't collect exceptions when throw-all is guaranteed."); ComputedEST = EST_Dynamic; // Record the exceptions in this function's exception specification. for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), EEnd = Proto->exception_end(); E != EEnd; ++E) if (ExceptionsSeen.insert(Self->Context.getCanonicalType(*E))) Exceptions.push_back(*E); } void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) return; // FIXME: // // C++0x [except.spec]p14: // [An] implicit exception-specification specifies the type-id T if and // only if T is allowed by the exception-specification of a function directly // invoked by f's implicit definition; f shall allow all exceptions if any // function it directly invokes allows all exceptions, and f shall allow no // exceptions if every function it directly invokes allows no exceptions. // // Note in particular that if an implicit exception-specification is generated // for a function containing a throw-expression, that specification can still // be noexcept(true). // // Note also that 'directly invoked' is not defined in the standard, and there // is no indication that we should only consider potentially-evaluated calls. // // Ultimately we should implement the intent of the standard: the exception // specification should be the set of exceptions which can be thrown by the // implicit definition. For now, we assume that any non-nothrow expression can // throw any exception. if (Self->canThrow(E)) ComputedEST = EST_None; } bool Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, SourceLocation EqualLoc) { if (RequireCompleteType(Param->getLocation(), Param->getType(), diag::err_typecheck_decl_incomplete_type)) { Param->setInvalidDecl(); return true; } // C++ [dcl.fct.default]p5 // A default argument expression is implicitly converted (clause // 4) to the parameter type. The default argument expression has // the same semantic constraints as the initializer expression in // a declaration of a variable of the parameter type, using the // copy-initialization semantics (8.5). InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, Param); InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(), EqualLoc); InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(*this, &Arg, 1)); if (Result.isInvalid()) return true; Arg = Result.takeAs(); CheckImplicitConversions(Arg, EqualLoc); Arg = MaybeCreateExprWithCleanups(Arg); // Okay: add the default argument to the parameter Param->setDefaultArg(Arg); // We have already instantiated this parameter; provide each of the // instantiations with the uninstantiated default argument. UnparsedDefaultArgInstantiationsMap::iterator InstPos = UnparsedDefaultArgInstantiations.find(Param); if (InstPos != UnparsedDefaultArgInstantiations.end()) { for (unsigned I = 0, N = InstPos->second.size(); I != N; ++I) InstPos->second[I]->setUninstantiatedDefaultArg(Arg); // We're done tracking this parameter's instantiations. UnparsedDefaultArgInstantiations.erase(InstPos); } return false; } /// ActOnParamDefaultArgument - Check whether the default argument /// provided for a function parameter is well-formed. If so, attach it /// to the parameter declaration. void Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, Expr *DefaultArg) { if (!param || !DefaultArg) return; ParmVarDecl *Param = cast(param); UnparsedDefaultArgLocs.erase(Param); // Default arguments are only permitted in C++ if (!getLangOpts().CPlusPlus) { Diag(EqualLoc, diag::err_param_default_argument) << DefaultArg->getSourceRange(); Param->setInvalidDecl(); return; } // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) { Param->setInvalidDecl(); return; } // Check that the default argument is well-formed CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg, this); if (DefaultArgChecker.Visit(DefaultArg)) { Param->setInvalidDecl(); return; } SetParamDefaultArgument(Param, DefaultArg, EqualLoc); } /// ActOnParamUnparsedDefaultArgument - We've seen a default /// argument for a function parameter, but we can't parse it yet /// because we're inside a class definition. Note that this default /// argument will be parsed later. void Sema::ActOnParamUnparsedDefaultArgument(Decl *param, SourceLocation EqualLoc, SourceLocation ArgLoc) { if (!param) return; ParmVarDecl *Param = cast(param); if (Param) Param->setUnparsedDefaultArg(); UnparsedDefaultArgLocs[Param] = ArgLoc; } /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of /// the default argument for the parameter param failed. void Sema::ActOnParamDefaultArgumentError(Decl *param) { if (!param) return; ParmVarDecl *Param = cast(param); Param->setInvalidDecl(); UnparsedDefaultArgLocs.erase(Param); } /// CheckExtraCXXDefaultArguments - Check for any extra default /// arguments in the declarator, which is not a function declaration /// or definition and therefore is not permitted to have default /// arguments. This routine should be invoked for every declarator /// that is not a function declaration or definition. void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { // C++ [dcl.fct.default]p3 // A default argument expression shall be specified only in the // parameter-declaration-clause of a function declaration or in a // template-parameter (14.1). It shall not be specified for a // parameter pack. If it is specified in a // parameter-declaration-clause, it shall not occur within a // declarator or abstract-declarator of a parameter-declaration. for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorChunk &chunk = D.getTypeObject(i); if (chunk.Kind == DeclaratorChunk::Function) { for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) { ParmVarDecl *Param = cast(chunk.Fun.ArgInfo[argIdx].Param); if (Param->hasUnparsedDefaultArg()) { CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens; Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation()); delete Toks; chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0; } else if (Param->getDefaultArg()) { Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) << Param->getDefaultArg()->getSourceRange(); Param->setDefaultArg(0); } } } } } // MergeCXXFunctionDecl - Merge two declarations of the same C++ // function, once we already know that they have the same // type. Subroutine of MergeFunctionDecl. Returns true if there was an // error, false otherwise. bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S) { bool Invalid = false; // C++ [dcl.fct.default]p4: // For non-template functions, default arguments can be added in // later declarations of a function in the same // scope. Declarations in different scopes have completely // distinct sets of default arguments. That is, declarations in // inner scopes do not acquire default arguments from // declarations in outer scopes, and vice versa. In a given // function declaration, all parameters subsequent to a // parameter with a default argument shall have default // arguments supplied in this or previous declarations. A // default argument shall not be redefined by a later // declaration (not even to the same value). // // C++ [dcl.fct.default]p6: // Except for member functions of class templates, the default arguments // in a member function definition that appears outside of the class // definition are added to the set of default arguments provided by the // member function declaration in the class definition. for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) { ParmVarDecl *OldParam = Old->getParamDecl(p); ParmVarDecl *NewParam = New->getParamDecl(p); bool OldParamHasDfl = OldParam->hasDefaultArg(); bool NewParamHasDfl = NewParam->hasDefaultArg(); NamedDecl *ND = Old; if (S && !isDeclInScope(ND, New->getDeclContext(), S)) // Ignore default parameters of old decl if they are not in // the same scope. OldParamHasDfl = false; if (OldParamHasDfl && NewParamHasDfl) { unsigned DiagDefaultParamID = diag::err_param_default_argument_redefinition; // MSVC accepts that default parameters be redefined for member functions // of template class. The new default parameter's value is ignored. Invalid = true; if (getLangOpts().MicrosoftExt) { CXXMethodDecl* MD = dyn_cast(New); if (MD && MD->getParent()->getDescribedClassTemplate()) { // Merge the old default argument into the new parameter. NewParam->setHasInheritedDefaultArg(); if (OldParam->hasUninstantiatedDefaultArg()) NewParam->setUninstantiatedDefaultArg( OldParam->getUninstantiatedDefaultArg()); else NewParam->setDefaultArg(OldParam->getInit()); DiagDefaultParamID = diag::warn_param_default_argument_redefinition; Invalid = false; } } // FIXME: If we knew where the '=' was, we could easily provide a fix-it // hint here. Alternatively, we could walk the type-source information // for NewParam to find the last source location in the type... but it // isn't worth the effort right now. This is the kind of test case that // is hard to get right: // int f(int); // void g(int (*fp)(int) = f); // void g(int (*fp)(int) = &f); Diag(NewParam->getLocation(), DiagDefaultParamID) << NewParam->getDefaultArgRange(); // Look for the function declaration where the default argument was // actually written, which may be a declaration prior to Old. for (FunctionDecl *Older = Old->getPreviousDecl(); Older; Older = Older->getPreviousDecl()) { if (!Older->getParamDecl(p)->hasDefaultArg()) break; OldParam = Older->getParamDecl(p); } Diag(OldParam->getLocation(), diag::note_previous_definition) << OldParam->getDefaultArgRange(); } else if (OldParamHasDfl) { // Merge the old default argument into the new parameter. // It's important to use getInit() here; getDefaultArg() // strips off any top-level ExprWithCleanups. NewParam->setHasInheritedDefaultArg(); if (OldParam->hasUninstantiatedDefaultArg()) NewParam->setUninstantiatedDefaultArg( OldParam->getUninstantiatedDefaultArg()); else NewParam->setDefaultArg(OldParam->getInit()); } else if (NewParamHasDfl) { if (New->getDescribedFunctionTemplate()) { // Paragraph 4, quoted above, only applies to non-template functions. Diag(NewParam->getLocation(), diag::err_param_default_argument_template_redecl) << NewParam->getDefaultArgRange(); Diag(Old->getLocation(), diag::note_template_prev_declaration) << false; } else if (New->getTemplateSpecializationKind() != TSK_ImplicitInstantiation && New->getTemplateSpecializationKind() != TSK_Undeclared) { // C++ [temp.expr.spec]p21: // Default function arguments shall not be specified in a declaration // or a definition for one of the following explicit specializations: // - the explicit specialization of a function template; // - the explicit specialization of a member function template; // - the explicit specialization of a member function of a class // template where the class template specialization to which the // member function specialization belongs is implicitly // instantiated. Diag(NewParam->getLocation(), diag::err_template_spec_default_arg) << (New->getTemplateSpecializationKind() ==TSK_ExplicitSpecialization) << New->getDeclName() << NewParam->getDefaultArgRange(); } else if (New->getDeclContext()->isDependentContext()) { // C++ [dcl.fct.default]p6 (DR217): // Default arguments for a member function of a class template shall // be specified on the initial declaration of the member function // within the class template. // // Reading the tea leaves a bit in DR217 and its reference to DR205 // leads me to the conclusion that one cannot add default function // arguments for an out-of-line definition of a member function of a // dependent type. int WhichKind = 2; if (CXXRecordDecl *Record = dyn_cast(New->getDeclContext())) { if (Record->getDescribedClassTemplate()) WhichKind = 0; else if (isa(Record)) WhichKind = 1; else WhichKind = 2; } Diag(NewParam->getLocation(), diag::err_param_default_argument_member_template_redecl) << WhichKind << NewParam->getDefaultArgRange(); } else if (CXXConstructorDecl *Ctor = dyn_cast(New)) { CXXSpecialMember NewSM = getSpecialMember(Ctor), OldSM = getSpecialMember(cast(Old)); if (NewSM != OldSM) { Diag(NewParam->getLocation(),diag::warn_default_arg_makes_ctor_special) << NewParam->getDefaultArgRange() << NewSM; Diag(Old->getLocation(), diag::note_previous_declaration_special) << OldSM; } } } } // C++11 [dcl.constexpr]p1: If any declaration of a function or function // template has a constexpr specifier then all its declarations shall // contain the constexpr specifier. if (New->isConstexpr() != Old->isConstexpr()) { Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) << New << New->isConstexpr(); Diag(Old->getLocation(), diag::note_previous_declaration); Invalid = true; } if (CheckEquivalentExceptionSpec(Old, New)) Invalid = true; return Invalid; } /// \brief Merge the exception specifications of two variable declarations. /// /// This is called when there's a redeclaration of a VarDecl. The function /// checks if the redeclaration might have an exception specification and /// validates compatibility and merges the specs if necessary. void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) { // Shortcut if exceptions are disabled. if (!getLangOpts().CXXExceptions) return; assert(Context.hasSameType(New->getType(), Old->getType()) && "Should only be called if types are otherwise the same."); QualType NewType = New->getType(); QualType OldType = Old->getType(); // We're only interested in pointers and references to functions, as well // as pointers to member functions. if (const ReferenceType *R = NewType->getAs()) { NewType = R->getPointeeType(); OldType = OldType->getAs()->getPointeeType(); } else if (const PointerType *P = NewType->getAs()) { NewType = P->getPointeeType(); OldType = OldType->getAs()->getPointeeType(); } else if (const MemberPointerType *M = NewType->getAs()) { NewType = M->getPointeeType(); OldType = OldType->getAs()->getPointeeType(); } if (!NewType->isFunctionProtoType()) return; // There's lots of special cases for functions. For function pointers, system // libraries are hopefully not as broken so that we don't need these // workarounds. if (CheckEquivalentExceptionSpec( OldType->getAs(), Old->getLocation(), NewType->getAs(), New->getLocation())) { New->setInvalidDecl(); } } /// CheckCXXDefaultArguments - Verify that the default arguments for a /// function declaration are well-formed according to C++ /// [dcl.fct.default]. void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { unsigned NumParams = FD->getNumParams(); unsigned p; bool IsLambda = FD->getOverloadedOperator() == OO_Call && isa(FD) && cast(FD)->getParent()->isLambda(); // Find first parameter with a default argument for (p = 0; p < NumParams; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); if (Param->hasDefaultArg()) { // C++11 [expr.prim.lambda]p5: // [...] Default arguments (8.3.6) shall not be specified in the // parameter-declaration-clause of a lambda-declarator. // // FIXME: Core issue 974 strikes this sentence, we only provide an // extension warning. if (IsLambda) Diag(Param->getLocation(), diag::ext_lambda_default_arguments) << Param->getDefaultArgRange(); break; } } // C++ [dcl.fct.default]p4: // In a given function declaration, all parameters // subsequent to a parameter with a default argument shall // have default arguments supplied in this or previous // declarations. A default argument shall not be redefined // by a later declaration (not even to the same value). unsigned LastMissingDefaultArg = 0; for (; p < NumParams; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); if (!Param->hasDefaultArg()) { if (Param->isInvalidDecl()) /* We already complained about this parameter. */; else if (Param->getIdentifier()) Diag(Param->getLocation(), diag::err_param_default_argument_missing_name) << Param->getIdentifier(); else Diag(Param->getLocation(), diag::err_param_default_argument_missing); LastMissingDefaultArg = p; } } if (LastMissingDefaultArg > 0) { // Some default arguments were missing. Clear out all of the // default arguments up to (and including) the last missing // default argument, so that we leave the function parameters // in a semantically valid state. for (p = 0; p <= LastMissingDefaultArg; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); if (Param->hasDefaultArg()) { Param->setDefaultArg(0); } } } } // CheckConstexprParameterTypes - Check whether a function's parameter types // are all literal types. If so, return true. If not, produce a suitable // diagnostic and return false. static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD) { unsigned ArgIndex = 0; const FunctionProtoType *FT = FD->getType()->getAs(); for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(), e = FT->arg_type_end(); i != e; ++i, ++ArgIndex) { const ParmVarDecl *PD = FD->getParamDecl(ArgIndex); SourceLocation ParamLoc = PD->getLocation(); if (!(*i)->isDependentType() && SemaRef.RequireLiteralType(ParamLoc, *i, SemaRef.PDiag(diag::err_constexpr_non_literal_param) << ArgIndex+1 << PD->getSourceRange() << isa(FD))) return false; } return true; } // CheckConstexprFunctionDecl - Check whether a function declaration satisfies // the requirements of a constexpr function definition or a constexpr // constructor definition. If so, return true. If not, produce appropriate // diagnostics and return false. // // This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360. bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { const CXXMethodDecl *MD = dyn_cast(NewFD); if (MD && MD->isInstance()) { // C++11 [dcl.constexpr]p4: // The definition of a constexpr constructor shall satisfy the following // constraints: // - the class shall not have any virtual base classes; const CXXRecordDecl *RD = MD->getParent(); if (RD->getNumVBases()) { Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base) << isa(NewFD) << RD->isStruct() << RD->getNumVBases(); for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) Diag(I->getLocStart(), diag::note_constexpr_virtual_base_here) << I->getSourceRange(); return false; } } if (!isa(NewFD)) { // C++11 [dcl.constexpr]p3: // The definition of a constexpr function shall satisfy the following // constraints: // - it shall not be virtual; const CXXMethodDecl *Method = dyn_cast(NewFD); if (Method && Method->isVirtual()) { Diag(NewFD->getLocation(), diag::err_constexpr_virtual); // If it's not obvious why this function is virtual, find an overridden // function which uses the 'virtual' keyword. const CXXMethodDecl *WrittenVirtual = Method; while (!WrittenVirtual->isVirtualAsWritten()) WrittenVirtual = *WrittenVirtual->begin_overridden_methods(); if (WrittenVirtual != Method) Diag(WrittenVirtual->getLocation(), diag::note_overridden_virtual_function); return false; } // - its return type shall be a literal type; QualType RT = NewFD->getResultType(); if (!RT->isDependentType() && RequireLiteralType(NewFD->getLocation(), RT, PDiag(diag::err_constexpr_non_literal_return))) return false; } // - each of its parameter types shall be a literal type; if (!CheckConstexprParameterTypes(*this, NewFD)) return false; return true; } /// Check the given declaration statement is legal within a constexpr function /// body. C++0x [dcl.constexpr]p3,p4. /// /// \return true if the body is OK, false if we have diagnosed a problem. static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, DeclStmt *DS) { // C++0x [dcl.constexpr]p3 and p4: // The definition of a constexpr function(p3) or constructor(p4) [...] shall // contain only for (DeclStmt::decl_iterator DclIt = DS->decl_begin(), DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) { switch ((*DclIt)->getKind()) { case Decl::StaticAssert: case Decl::Using: case Decl::UsingShadow: case Decl::UsingDirective: case Decl::UnresolvedUsingTypename: // - static_assert-declarations // - using-declarations, // - using-directives, continue; case Decl::Typedef: case Decl::TypeAlias: { // - typedef declarations and alias-declarations that do not define // classes or enumerations, TypedefNameDecl *TN = cast(*DclIt); if (TN->getUnderlyingType()->isVariablyModifiedType()) { // Don't allow variably-modified types in constexpr functions. TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc(); SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla) << TL.getSourceRange() << TL.getType() << isa(Dcl); return false; } continue; } case Decl::Enum: case Decl::CXXRecord: // As an extension, we allow the declaration (but not the definition) of // classes and enumerations in all declarations, not just in typedef and // alias declarations. if (cast(*DclIt)->isThisDeclarationADefinition()) { SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_type_definition) << isa(Dcl); return false; } continue; case Decl::Var: SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration) << isa(Dcl); return false; default: SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt) << isa(Dcl); return false; } } return true; } /// Check that the given field is initialized within a constexpr constructor. /// /// \param Dcl The constexpr constructor being checked. /// \param Field The field being checked. This may be a member of an anonymous /// struct or union nested within the class being checked. /// \param Inits All declarations, including anonymous struct/union members and /// indirect members, for which any initialization was provided. /// \param Diagnosed Set to true if an error is produced. static void CheckConstexprCtorInitializer(Sema &SemaRef, const FunctionDecl *Dcl, FieldDecl *Field, llvm::SmallSet &Inits, bool &Diagnosed) { if (Field->isUnnamedBitfield()) return; if (Field->isAnonymousStructOrUnion() && Field->getType()->getAsCXXRecordDecl()->isEmpty()) return; if (!Inits.count(Field)) { if (!Diagnosed) { SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init); Diagnosed = true; } SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init); } else if (Field->isAnonymousStructOrUnion()) { const RecordDecl *RD = Field->getType()->castAs()->getDecl(); for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) // If an anonymous union contains an anonymous struct of which any member // is initialized, all members must be initialized. if (!RD->isUnion() || Inits.count(*I)) CheckConstexprCtorInitializer(SemaRef, Dcl, *I, Inits, Diagnosed); } } /// Check the body for the given constexpr function declaration only contains /// the permitted types of statement. C++11 [dcl.constexpr]p3,p4. /// /// \return true if the body is OK, false if we have diagnosed a problem. bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { if (isa(Body)) { // C++11 [dcl.constexpr]p3: // The definition of a constexpr function shall satisfy the following // constraints: [...] // - its function-body shall be = delete, = default, or a // compound-statement // // C++11 [dcl.constexpr]p4: // In the definition of a constexpr constructor, [...] // - its function-body shall not be a function-try-block; Diag(Body->getLocStart(), diag::err_constexpr_function_try_block) << isa(Dcl); return false; } // - its function-body shall be [...] a compound-statement that contains only CompoundStmt *CompBody = cast(Body); llvm::SmallVector ReturnStmts; for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(), BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) { switch ((*BodyIt)->getStmtClass()) { case Stmt::NullStmtClass: // - null statements, continue; case Stmt::DeclStmtClass: // - static_assert-declarations // - using-declarations, // - using-directives, // - typedef declarations and alias-declarations that do not define // classes or enumerations, if (!CheckConstexprDeclStmt(*this, Dcl, cast(*BodyIt))) return false; continue; case Stmt::ReturnStmtClass: // - and exactly one return statement; if (isa(Dcl)) break; ReturnStmts.push_back((*BodyIt)->getLocStart()); continue; default: break; } Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt) << isa(Dcl); return false; } if (const CXXConstructorDecl *Constructor = dyn_cast(Dcl)) { const CXXRecordDecl *RD = Constructor->getParent(); // DR1359: // - every non-variant non-static data member and base class sub-object // shall be initialized; // - if the class is a non-empty union, or for each non-empty anonymous // union member of a non-union class, exactly one non-static data member // shall be initialized; if (RD->isUnion()) { if (Constructor->getNumCtorInitializers() == 0 && !RD->isEmpty()) { Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init); return false; } } else if (!Constructor->isDependentContext() && !Constructor->isDelegatingConstructor()) { assert(RD->getNumVBases() == 0 && "constexpr ctor with virtual bases"); // Skip detailed checking if we have enough initializers, and we would // allow at most one initializer per member. bool AnyAnonStructUnionMembers = false; unsigned Fields = 0; for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++Fields) { if ((*I)->isAnonymousStructOrUnion()) { AnyAnonStructUnionMembers = true; break; } } if (AnyAnonStructUnionMembers || Constructor->getNumCtorInitializers() != RD->getNumBases() + Fields) { // Check initialization of non-static data members. Base classes are // always initialized so do not need to be checked. Dependent bases // might not have initializers in the member initializer list. llvm::SmallSet Inits; for (CXXConstructorDecl::init_const_iterator I = Constructor->init_begin(), E = Constructor->init_end(); I != E; ++I) { if (FieldDecl *FD = (*I)->getMember()) Inits.insert(FD); else if (IndirectFieldDecl *ID = (*I)->getIndirectMember()) Inits.insert(ID->chain_begin(), ID->chain_end()); } bool Diagnosed = false; for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) CheckConstexprCtorInitializer(*this, Dcl, *I, Inits, Diagnosed); if (Diagnosed) return false; } } } else { if (ReturnStmts.empty()) { Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return); return false; } if (ReturnStmts.size() > 1) { Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return); for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I) Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return); return false; } } // C++11 [dcl.constexpr]p5: // if no function argument values exist such that the function invocation // substitution would produce a constant expression, the program is // ill-formed; no diagnostic required. // C++11 [dcl.constexpr]p3: // - every constructor call and implicit conversion used in initializing the // return value shall be one of those allowed in a constant expression. // C++11 [dcl.constexpr]p4: // - every constructor involved in initializing non-static data members and // base class sub-objects shall be a constexpr constructor. llvm::SmallVector Diags; if (!Expr::isPotentialConstantExpr(Dcl, Diags)) { Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr) << isa(Dcl); for (size_t I = 0, N = Diags.size(); I != N; ++I) Diag(Diags[I].first, Diags[I].second); return false; } return true; } /// isCurrentClassName - Determine whether the identifier II is the /// name of the class type currently being defined. In the case of /// nested classes, this will only return true if II is the name of /// the innermost class. bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, const CXXScopeSpec *SS) { assert(getLangOpts().CPlusPlus && "No class names in C!"); CXXRecordDecl *CurDecl; if (SS && SS->isSet() && !SS->isInvalid()) { DeclContext *DC = computeDeclContext(*SS, true); CurDecl = dyn_cast_or_null(DC); } else CurDecl = dyn_cast_or_null(CurContext); if (CurDecl && CurDecl->getIdentifier()) return &II == CurDecl->getIdentifier(); else return false; } /// \brief Check the validity of a C++ base class specifier. /// /// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics /// and returns NULL otherwise. CXXBaseSpecifier * Sema::CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, TypeSourceInfo *TInfo, SourceLocation EllipsisLoc) { QualType BaseType = TInfo->getType(); // C++ [class.union]p1: // A union shall not have base classes. if (Class->isUnion()) { Diag(Class->getLocation(), diag::err_base_clause_on_union) << SpecifierRange; return 0; } if (EllipsisLoc.isValid() && !TInfo->getType()->containsUnexpandedParameterPack()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << TInfo->getTypeLoc().getSourceRange(); EllipsisLoc = SourceLocation(); } if (BaseType->isDependentType()) return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, Class->getTagKind() == TTK_Class, Access, TInfo, EllipsisLoc); SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc(); // Base specifiers must be record types. if (!BaseType->isRecordType()) { Diag(BaseLoc, diag::err_base_must_be_class) << SpecifierRange; return 0; } // C++ [class.union]p1: // A union shall not be used as a base class. if (BaseType->isUnionType()) { Diag(BaseLoc, diag::err_union_as_base_class) << SpecifierRange; return 0; } // C++ [class.derived]p2: // The class-name in a base-specifier shall not be an incompletely // defined class. if (RequireCompleteType(BaseLoc, BaseType, PDiag(diag::err_incomplete_base_class) << SpecifierRange)) { Class->setInvalidDecl(); return 0; } // If the base class is polymorphic or isn't empty, the new one is/isn't, too. RecordDecl *BaseDecl = BaseType->getAs()->getDecl(); assert(BaseDecl && "Record type has no declaration"); BaseDecl = BaseDecl->getDefinition(); assert(BaseDecl && "Base type is not incomplete, but has no definition"); CXXRecordDecl * CXXBaseDecl = cast(BaseDecl); assert(CXXBaseDecl && "Base type is not a C++ type"); // C++ [class]p3: // If a class is marked final and it appears as a base-type-specifier in // base-clause, the program is ill-formed. if (CXXBaseDecl->hasAttr()) { Diag(BaseLoc, diag::err_class_marked_final_used_as_base) << CXXBaseDecl->getDeclName(); Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl) << CXXBaseDecl->getDeclName(); return 0; } if (BaseDecl->isInvalidDecl()) Class->setInvalidDecl(); // Create the base specifier. return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, Class->getTagKind() == TTK_Class, Access, TInfo, EllipsisLoc); } /// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is /// one entry in the base class list of a class specifier, for /// example: /// class foo : public bar, virtual private baz { /// 'public bar' and 'virtual private baz' are each base-specifiers. BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, ParsedType basetype, SourceLocation BaseLoc, SourceLocation EllipsisLoc) { if (!classdecl) return true; AdjustDeclIfTemplate(classdecl); CXXRecordDecl *Class = dyn_cast(classdecl); if (!Class) return true; TypeSourceInfo *TInfo = 0; GetTypeFromParser(basetype, &TInfo); if (EllipsisLoc.isInvalid() && DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo, UPPC_BaseType)) return true; if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, Virtual, Access, TInfo, EllipsisLoc)) return BaseSpec; return true; } /// \brief Performs the actual work of attaching the given base class /// specifiers to a C++ class. bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, unsigned NumBases) { if (NumBases == 0) return false; // Used to keep track of which base types we have already seen, so // that we can properly diagnose redundant direct base types. Note // that the key is always the unqualified canonical type of the base // class. std::map KnownBaseTypes; // Copy non-redundant base specifiers into permanent storage. unsigned NumGoodBases = 0; bool Invalid = false; for (unsigned idx = 0; idx < NumBases; ++idx) { QualType NewBaseType = Context.getCanonicalType(Bases[idx]->getType()); NewBaseType = NewBaseType.getLocalUnqualifiedType(); CXXBaseSpecifier *&KnownBase = KnownBaseTypes[NewBaseType]; if (KnownBase) { // C++ [class.mi]p3: // A class shall not be specified as a direct base class of a // derived class more than once. Diag(Bases[idx]->getLocStart(), diag::err_duplicate_base_class) << KnownBase->getType() << Bases[idx]->getSourceRange(); // Delete the duplicate base class specifier; we're going to // overwrite its pointer later. Context.Deallocate(Bases[idx]); Invalid = true; } else { // Okay, add this new base class. KnownBase = Bases[idx]; Bases[NumGoodBases++] = Bases[idx]; if (const RecordType *Record = NewBaseType->getAs()) if (const CXXRecordDecl *RD = cast(Record->getDecl())) if (RD->hasAttr()) Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context)); } } // Attach the remaining base class specifiers to the derived class. Class->setBases(Bases, NumGoodBases); // Delete the remaining (good) base class specifiers, since their // data has been copied into the CXXRecordDecl. for (unsigned idx = 0; idx < NumGoodBases; ++idx) Context.Deallocate(Bases[idx]); return Invalid; } /// ActOnBaseSpecifiers - Attach the given base specifiers to the /// class, after checking whether there are any duplicate base /// classes. void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases, unsigned NumBases) { if (!ClassDecl || !Bases || !NumBases) return; AdjustDeclIfTemplate(ClassDecl); AttachBaseSpecifiers(cast(ClassDecl), (CXXBaseSpecifier**)(Bases), NumBases); } static CXXRecordDecl *GetClassForType(QualType T) { if (const RecordType *RT = T->getAs()) return cast(RT->getDecl()); else if (const InjectedClassNameType *ICT = T->getAs()) return ICT->getDecl(); else return 0; } /// \brief Determine whether the type \p Derived is a C++ class that is /// derived from the type \p Base. bool Sema::IsDerivedFrom(QualType Derived, QualType Base) { if (!getLangOpts().CPlusPlus) return false; CXXRecordDecl *DerivedRD = GetClassForType(Derived); if (!DerivedRD) return false; CXXRecordDecl *BaseRD = GetClassForType(Base); if (!BaseRD) return false; // FIXME: instantiate DerivedRD if necessary. We need a PoI for this. return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD); } /// \brief Determine whether the type \p Derived is a C++ class that is /// derived from the type \p Base. bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { if (!getLangOpts().CPlusPlus) return false; CXXRecordDecl *DerivedRD = GetClassForType(Derived); if (!DerivedRD) return false; CXXRecordDecl *BaseRD = GetClassForType(Base); if (!BaseRD) return false; return DerivedRD->isDerivedFrom(BaseRD, Paths); } void Sema::BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePathArray) { assert(BasePathArray.empty() && "Base path array must be empty!"); assert(Paths.isRecordingPaths() && "Must record paths!"); const CXXBasePath &Path = Paths.front(); // We first go backward and check if we have a virtual base. // FIXME: It would be better if CXXBasePath had the base specifier for // the nearest virtual base. unsigned Start = 0; for (unsigned I = Path.size(); I != 0; --I) { if (Path[I - 1].Base->isVirtual()) { Start = I - 1; break; } } // Now add all bases. for (unsigned I = Start, E = Path.size(); I != E; ++I) BasePathArray.push_back(const_cast(Path[I].Base)); } /// \brief Determine whether the given base path includes a virtual /// base class. bool Sema::BasePathInvolvesVirtualBase(const CXXCastPath &BasePath) { for (CXXCastPath::const_iterator B = BasePath.begin(), BEnd = BasePath.end(); B != BEnd; ++B) if ((*B)->isVirtual()) return true; return false; } /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base /// conversion (where Derived and Base are class types) is /// well-formed, meaning that the conversion is unambiguous (and /// that all of the base classes are accessible). Returns true /// and emits a diagnostic if the code is ill-formed, returns false /// otherwise. Loc is the location where this routine should point to /// if there is an error, and Range is the source range to highlight /// if there is an error. bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, CXXCastPath *BasePath) { // First, determine whether the path from Derived to Base is // ambiguous. This is slightly more expensive than checking whether // the Derived to Base conversion exists, because here we need to // explore multiple paths to determine if there is an ambiguity. CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); bool DerivationOkay = IsDerivedFrom(Derived, Base, Paths); assert(DerivationOkay && "Can only be used with a derived-to-base conversion"); (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { if (InaccessibleBaseID) { // Check that the base class can be accessed. switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), InaccessibleBaseID)) { case AR_inaccessible: return true; case AR_accessible: case AR_dependent: case AR_delayed: break; } } // Build a base path if necessary. if (BasePath) BuildBasePathArray(Paths, *BasePath); return false; } // We know that the derived-to-base conversion is ambiguous, and // we're going to produce a diagnostic. Perform the derived-to-base // search just one more time to compute all of the possible paths so // that we can print them out. This is more expensive than any of // the previous derived-to-base checks we've done, but at this point // performance isn't as much of an issue. Paths.clear(); Paths.setRecordingPaths(true); bool StillOkay = IsDerivedFrom(Derived, Base, Paths); assert(StillOkay && "Can only be used with a derived-to-base conversion"); (void)StillOkay; // Build up a textual representation of the ambiguous paths, e.g., // D -> B -> A, that will be used to illustrate the ambiguous // conversions in the diagnostic. We only print one of the paths // to each base class subobject. std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths); Diag(Loc, AmbigiousBaseConvID) << Derived << Base << PathDisplayStr << Range << Name; return true; } bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, CXXCastPath *BasePath, bool IgnoreAccess) { return CheckDerivedToBaseConversion(Derived, Base, IgnoreAccess ? 0 : diag::err_upcast_to_inaccessible_base, diag::err_ambiguous_derived_to_base_conv, Loc, Range, DeclarationName(), BasePath); } /// @brief Builds a string representing ambiguous paths from a /// specific derived class to different subobjects of the same base /// class. /// /// This function builds a string that can be used in error messages /// to show the different paths that one can take through the /// inheritance hierarchy to go from the derived class to different /// subobjects of a base class. The result looks something like this: /// @code /// struct D -> struct B -> struct A /// struct D -> struct C -> struct A /// @endcode std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { std::string PathDisplayStr; std::set DisplayedPaths; for (CXXBasePaths::paths_iterator Path = Paths.begin(); Path != Paths.end(); ++Path) { if (DisplayedPaths.insert(Path->back().SubobjectNumber).second) { // We haven't displayed a path to this particular base // class subobject yet. PathDisplayStr += "\n "; PathDisplayStr += Context.getTypeDeclType(Paths.getOrigin()).getAsString(); for (CXXBasePath::const_iterator Element = Path->begin(); Element != Path->end(); ++Element) PathDisplayStr += " -> " + Element->Base->getType().getAsString(); } } return PathDisplayStr; } //===----------------------------------------------------------------------===// // C++ class member Handling //===----------------------------------------------------------------------===// /// ActOnAccessSpecifier - Parsed an access specifier followed by a colon. bool Sema::ActOnAccessSpecifier(AccessSpecifier Access, SourceLocation ASLoc, SourceLocation ColonLoc, AttributeList *Attrs) { assert(Access != AS_none && "Invalid kind for syntactic access specifier!"); AccessSpecDecl *ASDecl = AccessSpecDecl::Create(Context, Access, CurContext, ASLoc, ColonLoc); CurContext->addHiddenDecl(ASDecl); return ProcessAccessDeclAttributeList(ASDecl, Attrs); } /// CheckOverrideControl - Check C++0x override control semantics. void Sema::CheckOverrideControl(const Decl *D) { const CXXMethodDecl *MD = dyn_cast(D); if (!MD || !MD->isVirtual()) return; if (MD->isDependentContext()) return; // C++0x [class.virtual]p3: // If a virtual function is marked with the virt-specifier override and does // not override a member function of a base class, // the program is ill-formed. bool HasOverriddenMethods = MD->begin_overridden_methods() != MD->end_overridden_methods(); if (MD->hasAttr() && !HasOverriddenMethods) { Diag(MD->getLocation(), diag::err_function_marked_override_not_overriding) << MD->getDeclName(); return; } } /// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member /// function overrides a virtual member function marked 'final', according to /// C++0x [class.virtual]p3. bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old) { if (!Old->hasAttr()) return false; Diag(New->getLocation(), diag::err_final_function_overridden) << New->getDeclName(); Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one, 'InitExpr' specifies the initializer if /// one has been parsed, and 'HasDeferredInit' is true if an initializer is /// present but parsing it has been deferred. Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, Expr *BW, const VirtSpecifiers &VS, bool HasDeferredInit) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); SourceLocation Loc = NameInfo.getLoc(); // For anonymous bitfields, the location should point to the type. if (Loc.isInvalid()) Loc = D.getLocStart(); Expr *BitWidth = static_cast(BW); assert(isa(CurContext)); assert(!DS.isFriendSpecified()); bool isFunc = D.isDeclarationOfFunction(); // C++ 9.2p6: A member shall not be declared to have automatic storage // duration (auto, register) or with the extern storage-class-specifier. // C++ 7.1.1p8: The mutable specifier can be applied only to names of class // data members and cannot be applied to names declared const or static, // and cannot be applied to reference members. switch (DS.getStorageClassSpec()) { case DeclSpec::SCS_unspecified: case DeclSpec::SCS_typedef: case DeclSpec::SCS_static: // FALL THROUGH. break; case DeclSpec::SCS_mutable: if (isFunc) { if (DS.getStorageClassSpecLoc().isValid()) Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function); else Diag(DS.getThreadSpecLoc(), diag::err_mutable_function); // FIXME: It would be nicer if the keyword was ignored only for this // declarator. Otherwise we could get follow-up errors. D.getMutableDeclSpec().ClearStorageClassSpecs(); } break; default: if (DS.getStorageClassSpecLoc().isValid()) Diag(DS.getStorageClassSpecLoc(), diag::err_storageclass_invalid_for_member); else Diag(DS.getThreadSpecLoc(), diag::err_storageclass_invalid_for_member); D.getMutableDeclSpec().ClearStorageClassSpecs(); } bool isInstField = ((DS.getStorageClassSpec() == DeclSpec::SCS_unspecified || DS.getStorageClassSpec() == DeclSpec::SCS_mutable) && !isFunc); Decl *Member; if (isInstField) { CXXScopeSpec &SS = D.getCXXScopeSpec(); // Data members must have identifiers for names. if (Name.getNameKind() != DeclarationName::Identifier) { Diag(Loc, diag::err_bad_variable_name) << Name; return 0; } IdentifierInfo *II = Name.getAsIdentifierInfo(); // Member field could not be with "template" keyword. // So TemplateParameterLists should be empty in this case. if (TemplateParameterLists.size()) { TemplateParameterList* TemplateParams = TemplateParameterLists.get()[0]; if (TemplateParams->size()) { // There is no such thing as a member field template. Diag(D.getIdentifierLoc(), diag::err_template_member) << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); } else { // There is an extraneous 'template<>' for this member. Diag(TemplateParams->getTemplateLoc(), diag::err_template_member_noparams) << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); } return 0; } if (SS.isSet() && !SS.isInvalid()) { // The user provided a superfluous scope specifier inside a class // definition: // // class X { // int X::member; // }; if (DeclContext *DC = computeDeclContext(SS, false)) diagnoseQualifiedDeclaration(SS, DC, Name, D.getIdentifierLoc()); else Diag(D.getIdentifierLoc(), diag::err_member_qualification) << Name << SS.getRange(); SS.clear(); } Member = HandleField(S, cast(CurContext), Loc, D, BitWidth, HasDeferredInit, AS); assert(Member && "HandleField never returns null"); } else { assert(!HasDeferredInit); Member = HandleDeclarator(S, D, move(TemplateParameterLists)); if (!Member) { return 0; } // Non-instance-fields can't have a bitfield. if (BitWidth) { if (Member->isInvalidDecl()) { // don't emit another diagnostic. } else if (isa(Member)) { // C++ 9.6p3: A bit-field shall not be a static member. // "static member 'A' cannot be a bit-field" Diag(Loc, diag::err_static_not_bitfield) << Name << BitWidth->getSourceRange(); } else if (isa(Member)) { // "typedef member 'x' cannot be a bit-field" Diag(Loc, diag::err_typedef_not_bitfield) << Name << BitWidth->getSourceRange(); } else { // A function typedef ("typedef int f(); f a;"). // C++ 9.6p3: A bit-field shall have integral or enumeration type. Diag(Loc, diag::err_not_integral_type_bitfield) << Name << cast(Member)->getType() << BitWidth->getSourceRange(); } BitWidth = 0; Member->setInvalidDecl(); } Member->setAccess(AS); // If we have declared a member function template, set the access of the // templated declaration as well. if (FunctionTemplateDecl *FunTmpl = dyn_cast(Member)) FunTmpl->getTemplatedDecl()->setAccess(AS); } if (VS.isOverrideSpecified()) { CXXMethodDecl *MD = dyn_cast(Member); if (!MD || !MD->isVirtual()) { Diag(Member->getLocStart(), diag::override_keyword_only_allowed_on_virtual_member_functions) << "override" << FixItHint::CreateRemoval(VS.getOverrideLoc()); } else MD->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context)); } if (VS.isFinalSpecified()) { CXXMethodDecl *MD = dyn_cast(Member); if (!MD || !MD->isVirtual()) { Diag(Member->getLocStart(), diag::override_keyword_only_allowed_on_virtual_member_functions) << "final" << FixItHint::CreateRemoval(VS.getFinalLoc()); } else MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); } if (VS.getLastLocation().isValid()) { // Update the end location of a method that has a virt-specifiers. if (CXXMethodDecl *MD = dyn_cast_or_null(Member)) MD->setRangeEnd(VS.getLastLocation()); } CheckOverrideControl(Member); assert((Name || isInstField) && "No identifier for non-field ?"); if (isInstField) FieldCollector->Add(cast(Member)); return Member; } /// ActOnCXXInClassMemberInitializer - This is invoked after parsing an /// in-class initializer for a non-static C++ class member, and after /// instantiating an in-class initializer in a class template. Such actions /// are deferred until the class is complete. void Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, Expr *InitExpr) { FieldDecl *FD = cast(D); if (!InitExpr) { FD->setInvalidDecl(); FD->removeInClassInitializer(); return; } if (DiagnoseUnexpandedParameterPack(InitExpr, UPPC_Initializer)) { FD->setInvalidDecl(); FD->removeInClassInitializer(); return; } ExprResult Init = InitExpr; if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { if (isa(InitExpr) && isStdInitializerList(FD->getType(), 0)) { Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list) << /*at end of ctor*/1 << InitExpr->getSourceRange(); } Expr **Inits = &InitExpr; unsigned NumInits = 1; InitializedEntity Entity = InitializedEntity::InitializeMember(FD); InitializationKind Kind = EqualLoc.isInvalid() ? InitializationKind::CreateDirectList(InitExpr->getLocStart()) : InitializationKind::CreateCopy(InitExpr->getLocStart(), EqualLoc); InitializationSequence Seq(*this, Entity, Kind, Inits, NumInits); Init = Seq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (Init.isInvalid()) { FD->setInvalidDecl(); return; } CheckImplicitConversions(Init.get(), EqualLoc); } // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. Init = MaybeCreateExprWithCleanups(Init); if (Init.isInvalid()) { FD->setInvalidDecl(); return; } InitExpr = Init.release(); FD->setInClassInitializer(InitExpr); } /// \brief Find the direct and/or virtual base specifiers that /// correspond to the given base type, for use in base initialization /// within a constructor. static bool FindBaseInitializer(Sema &SemaRef, CXXRecordDecl *ClassDecl, QualType BaseType, const CXXBaseSpecifier *&DirectBaseSpec, const CXXBaseSpecifier *&VirtualBaseSpec) { // First, check for a direct base class. DirectBaseSpec = 0; for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) { if (SemaRef.Context.hasSameUnqualifiedType(BaseType, Base->getType())) { // We found a direct base of this type. That's what we're // initializing. DirectBaseSpec = &*Base; break; } } // Check for a virtual base class. // FIXME: We might be able to short-circuit this if we know in advance that // there are no virtual bases. VirtualBaseSpec = 0; if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) { // We haven't found a base yet; search the class hierarchy for a // virtual base class. CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); if (SemaRef.IsDerivedFrom(SemaRef.Context.getTypeDeclType(ClassDecl), BaseType, Paths)) { for (CXXBasePaths::paths_iterator Path = Paths.begin(); Path != Paths.end(); ++Path) { if (Path->back().Base->isVirtual()) { VirtualBaseSpec = Path->back().Base; break; } } } } return DirectBaseSpec || VirtualBaseSpec; } /// \brief Handle a C++ member initializer using braced-init-list syntax. MemInitResult Sema::ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *InitList, SourceLocation EllipsisLoc) { return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, DS, IdLoc, InitList, EllipsisLoc); } /// \brief Handle a C++ member initializer using parentheses syntax. MemInitResult Sema::ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, SourceLocation EllipsisLoc) { Expr *List = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, RParenLoc); return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, DS, IdLoc, List, EllipsisLoc); } namespace { // Callback to only accept typo corrections that can be a valid C++ member // intializer: either a non-static field member or a base class. class MemInitializerValidatorCCC : public CorrectionCandidateCallback { public: explicit MemInitializerValidatorCCC(CXXRecordDecl *ClassDecl) : ClassDecl(ClassDecl) {} virtual bool ValidateCandidate(const TypoCorrection &candidate) { if (NamedDecl *ND = candidate.getCorrectionDecl()) { if (FieldDecl *Member = dyn_cast(ND)) return Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl); else return isa(ND); } return false; } private: CXXRecordDecl *ClassDecl; }; } /// \brief Handle a C++ member initializer. MemInitResult Sema::BuildMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *Init, SourceLocation EllipsisLoc) { if (!ConstructorD) return true; AdjustDeclIfTemplate(ConstructorD); CXXConstructorDecl *Constructor = dyn_cast(ConstructorD); if (!Constructor) { // The user wrote a constructor initializer on a function that is // not a C++ constructor. Ignore the error for now, because we may // have more member initializers coming; we'll diagnose it just // once in ActOnMemInitializers. return true; } CXXRecordDecl *ClassDecl = Constructor->getParent(); // C++ [class.base.init]p2: // Names in a mem-initializer-id are looked up in the scope of the // constructor's class and, if not found in that scope, are looked // up in the scope containing the constructor's definition. // [Note: if the constructor's class contains a member with the // same name as a direct or virtual base class of the class, a // mem-initializer-id naming the member or base class and composed // of a single identifier refers to the class member. A // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] if (!SS.getScopeRep() && !TemplateTypeTy) { // Look for a member, first. DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); if (Result.first != Result.second) { ValueDecl *Member; if ((Member = dyn_cast(*Result.first)) || (Member = dyn_cast(*Result.first))) { if (EllipsisLoc.isValid()) Diag(EllipsisLoc, diag::err_pack_expansion_member_init) << MemberOrBase << SourceRange(IdLoc, Init->getSourceRange().getEnd()); return BuildMemberInitializer(Member, Init, IdLoc); } } } // It didn't name a member, so see if it names a class. QualType BaseType; TypeSourceInfo *TInfo = 0; if (TemplateTypeTy) { BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo); } else if (DS.getTypeSpecType() == TST_decltype) { BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); } else { LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName); LookupParsedName(R, S, &SS); TypeDecl *TyD = R.getAsSingle(); if (!TyD) { if (R.isAmbiguous()) return true; // We don't want access-control diagnostics here. R.suppressDiagnostics(); if (SS.isSet() && isDependentScopeSpecifier(SS)) { bool NotUnknownSpecialization = false; DeclContext *DC = computeDeclContext(SS, false); if (CXXRecordDecl *Record = dyn_cast_or_null(DC)) NotUnknownSpecialization = !Record->hasAnyDependentBases(); if (!NotUnknownSpecialization) { // When the scope specifier can refer to a member of an unknown // specialization, we take it as a type name. BaseType = CheckTypenameType(ETK_None, SourceLocation(), SS.getWithLocInContext(Context), *MemberOrBase, IdLoc); if (BaseType.isNull()) return true; R.clear(); R.setLookupName(MemberOrBase); } } // If no results were found, try to correct typos. TypoCorrection Corr; MemInitializerValidatorCCC Validator(ClassDecl); if (R.empty() && BaseType.isNull() && (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS, Validator, ClassDecl))) { std::string CorrectedStr(Corr.getAsString(getLangOpts())); std::string CorrectedQuotedStr(Corr.getQuoted(getLangOpts())); if (FieldDecl *Member = Corr.getCorrectionDeclAs()) { // We have found a non-static data member with a similar // name to what was typed; complain and initialize that // member. Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) << MemberOrBase << true << CorrectedQuotedStr << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); Diag(Member->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; return BuildMemberInitializer(Member, Init, IdLoc); } else if (TypeDecl *Type = Corr.getCorrectionDeclAs()) { const CXXBaseSpecifier *DirectBaseSpec; const CXXBaseSpecifier *VirtualBaseSpec; if (FindBaseInitializer(*this, ClassDecl, Context.getTypeDeclType(Type), DirectBaseSpec, VirtualBaseSpec)) { // We have found a direct or virtual base class with a // similar name to what was typed; complain and initialize // that base class. Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) << MemberOrBase << false << CorrectedQuotedStr << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec : VirtualBaseSpec; Diag(BaseSpec->getLocStart(), diag::note_base_class_specified_here) << BaseSpec->getType() << BaseSpec->getSourceRange(); TyD = Type; } } } if (!TyD && BaseType.isNull()) { Diag(IdLoc, diag::err_mem_init_not_member_or_class) << MemberOrBase << SourceRange(IdLoc,Init->getSourceRange().getEnd()); return true; } } if (BaseType.isNull()) { BaseType = Context.getTypeDeclType(TyD); if (SS.isSet()) { NestedNameSpecifier *Qualifier = static_cast(SS.getScopeRep()); // FIXME: preserve source range information BaseType = Context.getElaboratedType(ETK_None, Qualifier, BaseType); } } } if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc); return BuildBaseInitializer(BaseType, TInfo, Init, ClassDecl, EllipsisLoc); } /// Checks a member initializer expression for cases where reference (or /// pointer) members are bound to by-value parameters (or their addresses). static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member, Expr *Init, SourceLocation IdLoc) { QualType MemberTy = Member->getType(); // We only handle pointers and references currently. // FIXME: Would this be relevant for ObjC object pointers? Or block pointers? if (!MemberTy->isReferenceType() && !MemberTy->isPointerType()) return; const bool IsPointer = MemberTy->isPointerType(); if (IsPointer) { if (const UnaryOperator *Op = dyn_cast(Init->IgnoreParenImpCasts())) { // The only case we're worried about with pointers requires taking the // address. if (Op->getOpcode() != UO_AddrOf) return; Init = Op->getSubExpr(); } else { // We only handle address-of expression initializers for pointers. return; } } if (isa(Init->IgnoreParens())) { // Taking the address of a temporary will be diagnosed as a hard error. if (IsPointer) return; S.Diag(Init->getExprLoc(), diag::warn_bind_ref_member_to_temporary) << Member << Init->getSourceRange(); } else if (const DeclRefExpr *DRE = dyn_cast(Init->IgnoreParens())) { // We only warn when referring to a non-reference parameter declaration. const ParmVarDecl *Parameter = dyn_cast(DRE->getDecl()); if (!Parameter || Parameter->getType()->isReferenceType()) return; S.Diag(Init->getExprLoc(), IsPointer ? diag::warn_init_ptr_member_to_parameter_addr : diag::warn_bind_ref_member_to_parameter) << Member << Parameter << Init->getSourceRange(); } else { // Other initializers are fine. return; } S.Diag(Member->getLocation(), diag::note_ref_or_ptr_member_declared_here) << (unsigned)IsPointer; } /// Checks an initializer expression for use of uninitialized fields, such as /// containing the field that is being initialized. Returns true if there is an /// uninitialized field was used an updates the SourceLocation parameter; false /// otherwise. static bool InitExprContainsUninitializedFields(const Stmt *S, const ValueDecl *LhsField, SourceLocation *L) { assert(isa(LhsField) || isa(LhsField)); if (isa(S)) { // Do not descend into function calls or constructors, as the use // of an uninitialized field may be valid. One would have to inspect // the contents of the function/ctor to determine if it is safe or not. // i.e. Pass-by-value is never safe, but pass-by-reference and pointers // may be safe, depending on what the function/ctor does. return false; } if (const MemberExpr *ME = dyn_cast(S)) { const NamedDecl *RhsField = ME->getMemberDecl(); if (const VarDecl *VD = dyn_cast(RhsField)) { // The member expression points to a static data member. assert(VD->isStaticDataMember() && "Member points to non-static data member!"); (void)VD; return false; } if (isa(RhsField)) { // The member expression points to an enum. return false; } if (RhsField == LhsField) { // Initializing a field with itself. Throw a warning. // But wait; there are exceptions! // Exception #1: The field may not belong to this record. // e.g. Foo(const Foo& rhs) : A(rhs.A) {} const Expr *base = ME->getBase(); if (base != NULL && !isa(base->IgnoreParenCasts())) { // Even though the field matches, it does not belong to this record. return false; } // None of the exceptions triggered; return true to indicate an // uninitialized field was used. *L = ME->getMemberLoc(); return true; } } else if (isa(S)) { // sizeof/alignof doesn't reference contents, do not warn. return false; } else if (const UnaryOperator *UOE = dyn_cast(S)) { // address-of doesn't reference contents (the pointer may be dereferenced // in the same expression but it would be rare; and weird). if (UOE->getOpcode() == UO_AddrOf) return false; } for (Stmt::const_child_range it = S->children(); it; ++it) { if (!*it) { // An expression such as 'member(arg ?: "")' may trigger this. continue; } if (InitExprContainsUninitializedFields(*it, LhsField, L)) return true; } return false; } MemInitResult Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, SourceLocation IdLoc) { FieldDecl *DirectMember = dyn_cast(Member); IndirectFieldDecl *IndirectMember = dyn_cast(Member); assert((DirectMember || IndirectMember) && "Member must be a FieldDecl or IndirectFieldDecl"); if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer)) return true; if (Member->isInvalidDecl()) return true; // Diagnose value-uses of fields to initialize themselves, e.g. // foo(foo) // where foo is not also a parameter to the constructor. // TODO: implement -Wuninitialized and fold this into that framework. Expr **Args; unsigned NumArgs; if (ParenListExpr *ParenList = dyn_cast(Init)) { Args = ParenList->getExprs(); NumArgs = ParenList->getNumExprs(); } else { InitListExpr *InitList = cast(Init); Args = InitList->getInits(); NumArgs = InitList->getNumInits(); } for (unsigned i = 0; i < NumArgs; ++i) { SourceLocation L; if (InitExprContainsUninitializedFields(Args[i], Member, &L)) { // FIXME: Return true in the case when other fields are used before being // uninitialized. For example, let this field be the i'th field. When // initializing the i'th field, throw a warning if any of the >= i'th // fields are used, as they are not yet initialized. // Right now we are only handling the case where the i'th field uses // itself in its initializer. Diag(L, diag::warn_field_is_uninit); } } SourceRange InitRange = Init->getSourceRange(); if (Member->getType()->isDependentType() || Init->isTypeDependent()) { // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. DiscardCleanupsInEvaluationContext(); } else { bool InitList = false; if (isa(Init)) { InitList = true; Args = &Init; NumArgs = 1; if (isStdInitializerList(Member->getType(), 0)) { Diag(IdLoc, diag::warn_dangling_std_initializer_list) << /*at end of ctor*/1 << InitRange; } } // Initialize the member. InitializedEntity MemberEntity = DirectMember ? InitializedEntity::InitializeMember(DirectMember, 0) : InitializedEntity::InitializeMember(IndirectMember, 0); InitializationKind Kind = InitList ? InitializationKind::CreateDirectList(IdLoc) : InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(), InitRange.getEnd()); InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, MultiExprArg(*this, Args, NumArgs), 0); if (MemberInit.isInvalid()) return true; CheckImplicitConversions(MemberInit.get(), InitRange.getBegin()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. MemberInit = MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) return true; // If we are in a dependent context, template instantiation will // perform this type-checking again. Just save the arguments that we // received. // FIXME: This isn't quite ideal, since our ASTs don't capture all // of the information that we have about the member // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. if (CurContext->isDependentContext()) { // The existing Init will do fine. } else { Init = MemberInit.get(); CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc); } } if (DirectMember) { return new (Context) CXXCtorInitializer(Context, DirectMember, IdLoc, InitRange.getBegin(), Init, InitRange.getEnd()); } else { return new (Context) CXXCtorInitializer(Context, IndirectMember, IdLoc, InitRange.getBegin(), Init, InitRange.getEnd()); } } MemInitResult Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, CXXRecordDecl *ClassDecl) { SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!LangOpts.CPlusPlus0x) return Diag(NameLoc, diag::err_delegating_ctor) << TInfo->getTypeLoc().getLocalSourceRange(); Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor); bool InitList = true; Expr **Args = &Init; unsigned NumArgs = 1; if (ParenListExpr *ParenList = dyn_cast(Init)) { InitList = false; Args = ParenList->getExprs(); NumArgs = ParenList->getNumExprs(); } SourceRange InitRange = Init->getSourceRange(); // Initialize the object. InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation( QualType(ClassDecl->getTypeForDecl(), 0)); InitializationKind Kind = InitList ? InitializationKind::CreateDirectList(NameLoc) : InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(), InitRange.getEnd()); InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs); ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind, MultiExprArg(*this, Args,NumArgs), 0); if (DelegationInit.isInvalid()) return true; assert(cast(DelegationInit.get())->getConstructor() && "Delegating constructor with no target?"); CheckImplicitConversions(DelegationInit.get(), InitRange.getBegin()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. DelegationInit = MaybeCreateExprWithCleanups(DelegationInit); if (DelegationInit.isInvalid()) return true; return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(), DelegationInit.takeAs(), InitRange.getEnd()); } MemInitResult Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Expr *Init, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc) { SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!BaseType->isDependentType() && !BaseType->isRecordType()) return Diag(BaseLoc, diag::err_base_init_does_not_name_class) << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); // C++ [class.base.init]p2: // [...] Unless the mem-initializer-id names a nonstatic data // member of the constructor's class or a direct or virtual base // of that class, the mem-initializer is ill-formed. A // mem-initializer-list can initialize a base class using any // name that denotes that base class type. bool Dependent = BaseType->isDependentType() || Init->isTypeDependent(); SourceRange InitRange = Init->getSourceRange(); if (EllipsisLoc.isValid()) { // This is a pack expansion. if (!BaseType->containsUnexpandedParameterPack()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << SourceRange(BaseLoc, InitRange.getEnd()); EllipsisLoc = SourceLocation(); } } else { // Check for any unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(BaseLoc, BaseTInfo, UPPC_Initializer)) return true; if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer)) return true; } // Check for direct and virtual base classes. const CXXBaseSpecifier *DirectBaseSpec = 0; const CXXBaseSpecifier *VirtualBaseSpec = 0; if (!Dependent) { if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0), BaseType)) return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl); FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, VirtualBaseSpec); // C++ [base.class.init]p2: // Unless the mem-initializer-id names a nonstatic data member of the // constructor's class or a direct or virtual base of that class, the // mem-initializer is ill-formed. if (!DirectBaseSpec && !VirtualBaseSpec) { // If the class has any dependent bases, then it's possible that // one of those types will resolve to the same type as // BaseType. Therefore, just treat this as a dependent base // class initialization. FIXME: Should we try to check the // initialization anyway? It seems odd. if (ClassDecl->hasAnyDependentBases()) Dependent = true; else return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) << BaseType << Context.getTypeDeclType(ClassDecl) << BaseTInfo->getTypeLoc().getLocalSourceRange(); } } if (Dependent) { DiscardCleanupsInEvaluationContext(); return new (Context) CXXCtorInitializer(Context, BaseTInfo, /*IsVirtual=*/false, InitRange.getBegin(), Init, InitRange.getEnd(), EllipsisLoc); } // C++ [base.class.init]p2: // If a mem-initializer-id is ambiguous because it designates both // a direct non-virtual base class and an inherited virtual base // class, the mem-initializer is ill-formed. if (DirectBaseSpec && VirtualBaseSpec) return Diag(BaseLoc, diag::err_base_init_direct_and_virtual) << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); CXXBaseSpecifier *BaseSpec = const_cast(DirectBaseSpec); if (!BaseSpec) BaseSpec = const_cast(VirtualBaseSpec); // Initialize the base. bool InitList = true; Expr **Args = &Init; unsigned NumArgs = 1; if (ParenListExpr *ParenList = dyn_cast(Init)) { InitList = false; Args = ParenList->getExprs(); NumArgs = ParenList->getNumExprs(); } InitializedEntity BaseEntity = InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec); InitializationKind Kind = InitList ? InitializationKind::CreateDirectList(BaseLoc) : InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(), InitRange.getEnd()); InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs); ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, MultiExprArg(*this, Args, NumArgs), 0); if (BaseInit.isInvalid()) return true; CheckImplicitConversions(BaseInit.get(), InitRange.getBegin()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. BaseInit = MaybeCreateExprWithCleanups(BaseInit); if (BaseInit.isInvalid()) return true; // If we are in a dependent context, template instantiation will // perform this type-checking again. Just save the arguments that we // received in a ParenListExpr. // FIXME: This isn't quite ideal, since our ASTs don't capture all // of the information that we have about the base // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. if (CurContext->isDependentContext()) BaseInit = Owned(Init); return new (Context) CXXCtorInitializer(Context, BaseTInfo, BaseSpec->isVirtual(), InitRange.getBegin(), BaseInit.takeAs(), InitRange.getEnd(), EllipsisLoc); } // Create a static_cast\(expr). static Expr *CastForMoving(Sema &SemaRef, Expr *E) { QualType ExprType = E->getType(); QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType); SourceLocation ExprLoc = E->getLocStart(); TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo( TargetType, ExprLoc); return SemaRef.BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E, SourceRange(ExprLoc, ExprLoc), E->getSourceRange()).take(); } /// ImplicitInitializerKind - How an implicit base or member initializer should /// initialize its base or member. enum ImplicitInitializerKind { IIK_Default, IIK_Copy, IIK_Move }; static bool BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ImplicitInitializerKind ImplicitInitKind, CXXBaseSpecifier *BaseSpec, bool IsInheritedVirtualBase, CXXCtorInitializer *&CXXBaseInit) { InitializedEntity InitEntity = InitializedEntity::InitializeBase(SemaRef.Context, BaseSpec, IsInheritedVirtualBase); ExprResult BaseInit; switch (ImplicitInitKind) { case IIK_Default: { InitializationKind InitKind = InitializationKind::CreateDefault(Constructor->getLocation()); InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg(SemaRef, 0, 0)); break; } case IIK_Move: case IIK_Copy: { bool Moving = ImplicitInitKind == IIK_Move; ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); Expr *CopyCtorArg = DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), SourceLocation(), Param, false, Constructor->getLocation(), ParamType, VK_LValue, 0); SemaRef.MarkDeclRefReferenced(cast(CopyCtorArg)); // Cast to the base class to avoid ambiguities. QualType ArgTy = SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), ParamType.getQualifiers()); if (Moving) { CopyCtorArg = CastForMoving(SemaRef, CopyCtorArg); } CXXCastPath BasePath; BasePath.push_back(BaseSpec); CopyCtorArg = SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, CK_UncheckedDerivedToBase, Moving ? VK_XValue : VK_LValue, &BasePath).take(); InitializationKind InitKind = InitializationKind::CreateDirect(Constructor->getLocation(), SourceLocation(), SourceLocation()); InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, &CopyCtorArg, 1); BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg(&CopyCtorArg, 1)); break; } } BaseInit = SemaRef.MaybeCreateExprWithCleanups(BaseInit); if (BaseInit.isInvalid()) return true; CXXBaseInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(), SourceLocation()), BaseSpec->isVirtual(), SourceLocation(), BaseInit.takeAs(), SourceLocation(), SourceLocation()); return false; } static bool RefersToRValueRef(Expr *MemRef) { ValueDecl *Referenced = cast(MemRef)->getMemberDecl(); return Referenced->getType()->isRValueReferenceType(); } static bool BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ImplicitInitializerKind ImplicitInitKind, FieldDecl *Field, IndirectFieldDecl *Indirect, CXXCtorInitializer *&CXXMemberInit) { if (Field->isInvalidDecl()) return true; SourceLocation Loc = Constructor->getLocation(); if (ImplicitInitKind == IIK_Copy || ImplicitInitKind == IIK_Move) { bool Moving = ImplicitInitKind == IIK_Move; ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); // Suppress copying zero-width bitfields. if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0) return false; Expr *MemberExprBase = DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), SourceLocation(), Param, false, Loc, ParamType, VK_LValue, 0); SemaRef.MarkDeclRefReferenced(cast(MemberExprBase)); if (Moving) { MemberExprBase = CastForMoving(SemaRef, MemberExprBase); } // Build a reference to this field within the parameter. CXXScopeSpec SS; LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc, Sema::LookupMemberName); MemberLookup.addDecl(Indirect ? cast(Indirect) : cast(Field), AS_public); MemberLookup.resolveKind(); ExprResult CtorArg = SemaRef.BuildMemberReferenceExpr(MemberExprBase, ParamType, Loc, /*IsArrow=*/false, SS, /*TemplateKWLoc=*/SourceLocation(), /*FirstQualifierInScope=*/0, MemberLookup, /*TemplateArgs=*/0); if (CtorArg.isInvalid()) return true; // C++11 [class.copy]p15: // - if a member m has rvalue reference type T&&, it is direct-initialized // with static_cast(x.m); if (RefersToRValueRef(CtorArg.get())) { CtorArg = CastForMoving(SemaRef, CtorArg.take()); } // When the field we are copying is an array, create index variables for // each dimension of the array. We use these index variables to subscript // the source array, and other clients (e.g., CodeGen) will perform the // necessary iteration with these index variables. SmallVector IndexVariables; QualType BaseType = Field->getType(); QualType SizeType = SemaRef.Context.getSizeType(); bool InitializingArray = false; while (const ConstantArrayType *Array = SemaRef.Context.getAsConstantArrayType(BaseType)) { InitializingArray = true; // Create the iteration variable for this array index. IdentifierInfo *IterationVarName = 0; { SmallString<8> Str; llvm::raw_svector_ostream OS(Str); OS << "__i" << IndexVariables.size(); IterationVarName = &SemaRef.Context.Idents.get(OS.str()); } VarDecl *IterationVar = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, Loc, IterationVarName, SizeType, SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None, SC_None); IndexVariables.push_back(IterationVar); // Create a reference to the iteration variable. ExprResult IterationVarRef = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc); assert(!IterationVarRef.isInvalid() && "Reference to invented variable cannot fail!"); IterationVarRef = SemaRef.DefaultLvalueConversion(IterationVarRef.take()); assert(!IterationVarRef.isInvalid() && "Conversion of invented variable cannot fail!"); // Subscript the array with this iteration variable. CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.take(), Loc, IterationVarRef.take(), Loc); if (CtorArg.isInvalid()) return true; BaseType = Array->getElementType(); } // The array subscript expression is an lvalue, which is wrong for moving. if (Moving && InitializingArray) CtorArg = CastForMoving(SemaRef, CtorArg.take()); // Construct the entity that we will be initializing. For an array, this // will be first element in the array, which may require several levels // of array-subscript entities. SmallVector Entities; Entities.reserve(1 + IndexVariables.size()); if (Indirect) Entities.push_back(InitializedEntity::InitializeMember(Indirect)); else Entities.push_back(InitializedEntity::InitializeMember(Field)); for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context, 0, Entities.back())); // Direct-initialize to use the copy constructor. InitializationKind InitKind = InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation()); Expr *CtorArgE = CtorArg.takeAs(); InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, &CtorArgE, 1); ExprResult MemberInit = InitSeq.Perform(SemaRef, Entities.back(), InitKind, MultiExprArg(&CtorArgE, 1)); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) return true; if (Indirect) { assert(IndexVariables.size() == 0 && "Indirect field improperly initialized"); CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, Loc, Loc, MemberInit.takeAs(), Loc); } else CXXMemberInit = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc, Loc, MemberInit.takeAs(), Loc, IndexVariables.data(), IndexVariables.size()); return false; } assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!"); QualType FieldBaseElementType = SemaRef.Context.getBaseElementType(Field->getType()); if (FieldBaseElementType->isRecordType()) { InitializedEntity InitEntity = Indirect? InitializedEntity::InitializeMember(Indirect) : InitializedEntity::InitializeMember(Field); InitializationKind InitKind = InitializationKind::CreateDefault(Loc); InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); ExprResult MemberInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg()); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) return true; if (Indirect) CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, Loc, Loc, MemberInit.get(), Loc); else CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, Loc, Loc, MemberInit.get(), Loc); return false; } if (!Field->getParent()->isUnion()) { if (FieldBaseElementType->isReferenceType()) { SemaRef.Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) << (int)Constructor->isImplicit() << SemaRef.Context.getTagDeclType(Constructor->getParent()) << 0 << Field->getDeclName(); SemaRef.Diag(Field->getLocation(), diag::note_declared_at); return true; } if (FieldBaseElementType.isConstQualified()) { SemaRef.Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) << (int)Constructor->isImplicit() << SemaRef.Context.getTagDeclType(Constructor->getParent()) << 1 << Field->getDeclName(); SemaRef.Diag(Field->getLocation(), diag::note_declared_at); return true; } } if (SemaRef.getLangOpts().ObjCAutoRefCount && FieldBaseElementType->isObjCRetainableType() && FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None && FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { // Instant objects: // Default-initialize Objective-C pointers to NULL. CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, Loc, Loc, new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()), Loc); return false; } // Nothing to initialize. CXXMemberInit = 0; return false; } namespace { struct BaseAndFieldInfo { Sema &S; CXXConstructorDecl *Ctor; bool AnyErrorsInInits; ImplicitInitializerKind IIK; llvm::DenseMap AllBaseFields; SmallVector AllToInit; BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits) : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) { bool Generated = Ctor->isImplicit() || Ctor->isDefaulted(); if (Generated && Ctor->isCopyConstructor()) IIK = IIK_Copy; else if (Generated && Ctor->isMoveConstructor()) IIK = IIK_Move; else IIK = IIK_Default; } bool isImplicitCopyOrMove() const { switch (IIK) { case IIK_Copy: case IIK_Move: return true; case IIK_Default: return false; } llvm_unreachable("Invalid ImplicitInitializerKind!"); } }; } /// \brief Determine whether the given indirect field declaration is somewhere /// within an anonymous union. static bool isWithinAnonymousUnion(IndirectFieldDecl *F) { for (IndirectFieldDecl::chain_iterator C = F->chain_begin(), CEnd = F->chain_end(); C != CEnd; ++C) if (CXXRecordDecl *Record = dyn_cast((*C)->getDeclContext())) if (Record->isUnion()) return true; return false; } /// \brief Determine whether the given type is an incomplete or zero-lenfgth /// array type. static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) { if (T->isIncompleteArrayType()) return true; while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) { if (!ArrayT->getSize()) return true; T = ArrayT->getElementType(); } return false; } static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, FieldDecl *Field, IndirectFieldDecl *Indirect = 0) { // Overwhelmingly common case: we have a direct initializer for this field. if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field)) { Info.AllToInit.push_back(Init); return false; } // C++0x [class.base.init]p8: if the entity is a non-static data member that // has a brace-or-equal-initializer, the entity is initialized as specified // in [dcl.init]. if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) { CXXCtorInitializer *Init; if (Indirect) Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, SourceLocation(), SourceLocation(), 0, SourceLocation()); else Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, SourceLocation(), SourceLocation(), 0, SourceLocation()); Info.AllToInit.push_back(Init); return false; } // Don't build an implicit initializer for union members if none was // explicitly specified. if (Field->getParent()->isUnion() || (Indirect && isWithinAnonymousUnion(Indirect))) return false; // Don't initialize incomplete or zero-length arrays. if (isIncompleteOrZeroLengthArrayType(SemaRef.Context, Field->getType())) return false; // Don't try to build an implicit initializer if there were semantic // errors in any of the initializers (and therefore we might be // missing some that the user actually wrote). if (Info.AnyErrorsInInits || Field->isInvalidDecl()) return false; CXXCtorInitializer *Init = 0; if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Indirect, Init)) return true; if (Init) Info.AllToInit.push_back(Init); return false; } bool Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor, CXXCtorInitializer *Initializer) { assert(Initializer->isDelegatingInitializer()); Constructor->setNumCtorInitializers(1); CXXCtorInitializer **initializer = new (Context) CXXCtorInitializer*[1]; memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*)); Constructor->setCtorInitializers(initializer); if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) { MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor); DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation()); } DelegatingCtorDecls.push_back(Constructor); return false; } bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, CXXCtorInitializer **Initializers, unsigned NumInitializers, bool AnyErrors) { if (Constructor->isDependentContext()) { // Just store the initializers as written, they will be checked during // instantiation. if (NumInitializers > 0) { Constructor->setNumCtorInitializers(NumInitializers); CXXCtorInitializer **baseOrMemberInitializers = new (Context) CXXCtorInitializer*[NumInitializers]; memcpy(baseOrMemberInitializers, Initializers, NumInitializers * sizeof(CXXCtorInitializer*)); Constructor->setCtorInitializers(baseOrMemberInitializers); } return false; } BaseAndFieldInfo Info(*this, Constructor, AnyErrors); // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition(); if (!ClassDecl) return true; bool HadError = false; for (unsigned i = 0; i < NumInitializers; i++) { CXXCtorInitializer *Member = Initializers[i]; if (Member->isBaseInitializer()) Info.AllBaseFields[Member->getBaseClass()->getAs()] = Member; else Info.AllBaseFields[Member->getAnyMember()] = Member; } // Keep track of the direct virtual bases. llvm::SmallPtrSet DirectVBases; for (CXXRecordDecl::base_class_iterator I = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) { if (I->isVirtual()) DirectVBases.insert(I); } // Push virtual bases before others. for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) { if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup(VBase->getType()->getAs())) { Info.AllToInit.push_back(Value); } else if (!AnyErrors) { bool IsInheritedVirtualBase = !DirectVBases.count(VBase); CXXCtorInitializer *CXXBaseInit; if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, VBase, IsInheritedVirtualBase, CXXBaseInit)) { HadError = true; continue; } Info.AllToInit.push_back(CXXBaseInit); } } // Non-virtual bases. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { // Virtuals are in the virtual base list and already constructed. if (Base->isVirtual()) continue; if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup(Base->getType()->getAs())) { Info.AllToInit.push_back(Value); } else if (!AnyErrors) { CXXCtorInitializer *CXXBaseInit; if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK, Base, /*IsInheritedVirtualBase=*/false, CXXBaseInit)) { HadError = true; continue; } Info.AllToInit.push_back(CXXBaseInit); } } // Fields. for (DeclContext::decl_iterator Mem = ClassDecl->decls_begin(), MemEnd = ClassDecl->decls_end(); Mem != MemEnd; ++Mem) { if (FieldDecl *F = dyn_cast(*Mem)) { // C++ [class.bit]p2: // A declaration for a bit-field that omits the identifier declares an // unnamed bit-field. Unnamed bit-fields are not members and cannot be // initialized. if (F->isUnnamedBitfield()) continue; // If we're not generating the implicit copy/move constructor, then we'll // handle anonymous struct/union fields based on their individual // indirect fields. if (F->isAnonymousStructOrUnion() && Info.IIK == IIK_Default) continue; if (CollectFieldInitializer(*this, Info, F)) HadError = true; continue; } // Beyond this point, we only consider default initialization. if (Info.IIK != IIK_Default) continue; if (IndirectFieldDecl *F = dyn_cast(*Mem)) { if (F->getType()->isIncompleteArrayType()) { assert(ClassDecl->hasFlexibleArrayMember() && "Incomplete array type is not valid"); continue; } // Initialize each field of an anonymous struct individually. if (CollectFieldInitializer(*this, Info, F->getAnonField(), F)) HadError = true; continue; } } NumInitializers = Info.AllToInit.size(); if (NumInitializers > 0) { Constructor->setNumCtorInitializers(NumInitializers); CXXCtorInitializer **baseOrMemberInitializers = new (Context) CXXCtorInitializer*[NumInitializers]; memcpy(baseOrMemberInitializers, Info.AllToInit.data(), NumInitializers * sizeof(CXXCtorInitializer*)); Constructor->setCtorInitializers(baseOrMemberInitializers); // Constructors implicitly reference the base and member // destructors. MarkBaseAndMemberDestructorsReferenced(Constructor->getLocation(), Constructor->getParent()); } return HadError; } static void *GetKeyForTopLevelField(FieldDecl *Field) { // For anonymous unions, use the class declaration as the key. if (const RecordType *RT = Field->getType()->getAs()) { if (RT->getDecl()->isAnonymousStructOrUnion()) return static_cast(RT->getDecl()); } return static_cast(Field); } static void *GetKeyForBase(ASTContext &Context, QualType BaseType) { return const_cast(Context.getCanonicalType(BaseType).getTypePtr()); } static void *GetKeyForMember(ASTContext &Context, CXXCtorInitializer *Member) { if (!Member->isAnyMemberInitializer()) return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0)); // For fields injected into the class via declaration of an anonymous union, // use its anonymous union class declaration as the unique key. FieldDecl *Field = Member->getAnyMember(); // If the field is a member of an anonymous struct or union, our key // is the anonymous record decl that's a direct child of the class. RecordDecl *RD = Field->getParent(); if (RD->isAnonymousStructOrUnion()) { while (true) { RecordDecl *Parent = cast(RD->getDeclContext()); if (Parent->isAnonymousStructOrUnion()) RD = Parent; else break; } return static_cast(RD); } return static_cast(Field); } static void DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, const CXXConstructorDecl *Constructor, CXXCtorInitializer **Inits, unsigned NumInits) { if (Constructor->getDeclContext()->isDependentContext()) return; // Don't check initializers order unless the warning is enabled at the // location of at least one initializer. bool ShouldCheckOrder = false; for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) { CXXCtorInitializer *Init = Inits[InitIndex]; if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order, Init->getSourceLocation()) != DiagnosticsEngine::Ignored) { ShouldCheckOrder = true; break; } } if (!ShouldCheckOrder) return; // Build the list of bases and members in the order that they'll // actually be initialized. The explicit initializers should be in // this same order but may be missing things. SmallVector IdealInitKeys; const CXXRecordDecl *ClassDecl = Constructor->getParent(); // 1. Virtual bases. for (CXXRecordDecl::base_class_const_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase->getType())); // 2. Non-virtual bases. for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { if (Base->isVirtual()) continue; IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base->getType())); } // 3. Direct fields. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) { if (Field->isUnnamedBitfield()) continue; IdealInitKeys.push_back(GetKeyForTopLevelField(*Field)); } unsigned NumIdealInits = IdealInitKeys.size(); unsigned IdealIndex = 0; CXXCtorInitializer *PrevInit = 0; for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) { CXXCtorInitializer *Init = Inits[InitIndex]; void *InitKey = GetKeyForMember(SemaRef.Context, Init); // Scan forward to try to find this initializer in the idealized // initializers list. for (; IdealIndex != NumIdealInits; ++IdealIndex) if (InitKey == IdealInitKeys[IdealIndex]) break; // If we didn't find this initializer, it must be because we // scanned past it on a previous iteration. That can only // happen if we're out of order; emit a warning. if (IdealIndex == NumIdealInits && PrevInit) { Sema::SemaDiagnosticBuilder D = SemaRef.Diag(PrevInit->getSourceLocation(), diag::warn_initializer_out_of_order); if (PrevInit->isAnyMemberInitializer()) D << 0 << PrevInit->getAnyMember()->getDeclName(); else D << 1 << PrevInit->getTypeSourceInfo()->getType(); if (Init->isAnyMemberInitializer()) D << 0 << Init->getAnyMember()->getDeclName(); else D << 1 << Init->getTypeSourceInfo()->getType(); // Move back to the initializer's location in the ideal list. for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex) if (InitKey == IdealInitKeys[IdealIndex]) break; assert(IdealIndex != NumIdealInits && "initializer not found in initializer list"); } PrevInit = Init; } } namespace { bool CheckRedundantInit(Sema &S, CXXCtorInitializer *Init, CXXCtorInitializer *&PrevInit) { if (!PrevInit) { PrevInit = Init; return false; } if (FieldDecl *Field = Init->getMember()) S.Diag(Init->getSourceLocation(), diag::err_multiple_mem_initialization) << Field->getDeclName() << Init->getSourceRange(); else { const Type *BaseClass = Init->getBaseClass(); assert(BaseClass && "neither field nor base"); S.Diag(Init->getSourceLocation(), diag::err_multiple_base_initialization) << QualType(BaseClass, 0) << Init->getSourceRange(); } S.Diag(PrevInit->getSourceLocation(), diag::note_previous_initializer) << 0 << PrevInit->getSourceRange(); return true; } typedef std::pair UnionEntry; typedef llvm::DenseMap RedundantUnionMap; bool CheckRedundantUnionInit(Sema &S, CXXCtorInitializer *Init, RedundantUnionMap &Unions) { FieldDecl *Field = Init->getAnyMember(); RecordDecl *Parent = Field->getParent(); NamedDecl *Child = Field; while (Parent->isAnonymousStructOrUnion() || Parent->isUnion()) { if (Parent->isUnion()) { UnionEntry &En = Unions[Parent]; if (En.first && En.first != Child) { S.Diag(Init->getSourceLocation(), diag::err_multiple_mem_union_initialization) << Field->getDeclName() << Init->getSourceRange(); S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer) << 0 << En.second->getSourceRange(); return true; } if (!En.first) { En.first = Child; En.second = Init; } if (!Parent->isAnonymousStructOrUnion()) return false; } Child = Parent; Parent = cast(Parent->getDeclContext()); } return false; } } /// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(Decl *ConstructorDecl, SourceLocation ColonLoc, CXXCtorInitializer **meminits, unsigned NumMemInits, bool AnyErrors) { if (!ConstructorDecl) return; AdjustDeclIfTemplate(ConstructorDecl); CXXConstructorDecl *Constructor = dyn_cast(ConstructorDecl); if (!Constructor) { Diag(ColonLoc, diag::err_only_constructors_take_base_inits); return; } CXXCtorInitializer **MemInits = reinterpret_cast(meminits); // Mapping for the duplicate initializers check. // For member initializers, this is keyed with a FieldDecl*. // For base initializers, this is keyed with a Type*. llvm::DenseMap Members; // Mapping for the inconsistent anonymous-union initializers check. RedundantUnionMap MemberUnions; bool HadError = false; for (unsigned i = 0; i < NumMemInits; i++) { CXXCtorInitializer *Init = MemInits[i]; // Set the source order index. Init->setSourceOrder(i); if (Init->isAnyMemberInitializer()) { FieldDecl *Field = Init->getAnyMember(); if (CheckRedundantInit(*this, Init, Members[Field]) || CheckRedundantUnionInit(*this, Init, MemberUnions)) HadError = true; } else if (Init->isBaseInitializer()) { void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0)); if (CheckRedundantInit(*this, Init, Members[Key])) HadError = true; } else { assert(Init->isDelegatingInitializer()); // This must be the only initializer if (i != 0 || NumMemInits > 1) { Diag(MemInits[0]->getSourceLocation(), diag::err_delegating_initializer_alone) << MemInits[0]->getSourceRange(); HadError = true; // We will treat this as being the only initializer. } SetDelegatingInitializer(Constructor, MemInits[i]); // Return immediately as the initializer is set. return; } } if (HadError) return; DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits); SetCtorInitializers(Constructor, MemInits, NumMemInits, AnyErrors); } void Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, CXXRecordDecl *ClassDecl) { // Ignore dependent contexts. Also ignore unions, since their members never // have destructors implicitly called. if (ClassDecl->isDependentContext() || ClassDecl->isUnion()) return; // FIXME: all the access-control diagnostics are positioned on the // field/base declaration. That's probably good; that said, the // user might reasonably want to know why the destructor is being // emitted, and we currently don't say. // Non-static data members. for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { FieldDecl *Field = *I; if (Field->isInvalidDecl()) continue; // Don't destroy incomplete or zero-length arrays. if (isIncompleteOrZeroLengthArrayType(Context, Field->getType())) continue; QualType FieldType = Context.getBaseElementType(Field->getType()); const RecordType* RT = FieldType->getAs(); if (!RT) continue; CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); if (FieldClassDecl->isInvalidDecl()) continue; if (FieldClassDecl->hasIrrelevantDestructor()) continue; // The destructor for an implicit anonymous union member is never invoked. if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion()) continue; CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl); assert(Dtor && "No dtor found for FieldClassDecl!"); CheckDestructorAccess(Field->getLocation(), Dtor, PDiag(diag::err_access_dtor_field) << Field->getDeclName() << FieldType); MarkFunctionReferenced(Location, const_cast(Dtor)); DiagnoseUseOfDecl(Dtor, Location); } llvm::SmallPtrSet DirectVirtualBases; // Bases. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { // Bases are always records in a well-formed non-dependent class. const RecordType *RT = Base->getType()->getAs(); // Remember direct virtual bases. if (Base->isVirtual()) DirectVirtualBases.insert(RT); CXXRecordDecl *BaseClassDecl = cast(RT->getDecl()); // If our base class is invalid, we probably can't get its dtor anyway. if (BaseClassDecl->isInvalidDecl()) continue; if (BaseClassDecl->hasIrrelevantDestructor()) continue; CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl); assert(Dtor && "No dtor found for BaseClassDecl!"); // FIXME: caret should be on the start of the class name CheckDestructorAccess(Base->getLocStart(), Dtor, PDiag(diag::err_access_dtor_base) << Base->getType() << Base->getSourceRange(), Context.getTypeDeclType(ClassDecl)); MarkFunctionReferenced(Location, const_cast(Dtor)); DiagnoseUseOfDecl(Dtor, Location); } // Virtual bases. for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) { // Bases are always records in a well-formed non-dependent class. const RecordType *RT = VBase->getType()->castAs(); // Ignore direct virtual bases. if (DirectVirtualBases.count(RT)) continue; CXXRecordDecl *BaseClassDecl = cast(RT->getDecl()); // If our base class is invalid, we probably can't get its dtor anyway. if (BaseClassDecl->isInvalidDecl()) continue; if (BaseClassDecl->hasIrrelevantDestructor()) continue; CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl); assert(Dtor && "No dtor found for BaseClassDecl!"); CheckDestructorAccess(ClassDecl->getLocation(), Dtor, PDiag(diag::err_access_dtor_vbase) << VBase->getType(), Context.getTypeDeclType(ClassDecl)); MarkFunctionReferenced(Location, const_cast(Dtor)); DiagnoseUseOfDecl(Dtor, Location); } } void Sema::ActOnDefaultCtorInitializers(Decl *CDtorDecl) { if (!CDtorDecl) return; if (CXXConstructorDecl *Constructor = dyn_cast(CDtorDecl)) SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false); } bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, AbstractDiagSelID SelID) { if (SelID == -1) return RequireNonAbstractType(Loc, T, PDiag(DiagID)); else return RequireNonAbstractType(Loc, T, PDiag(DiagID) << SelID); } bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD) { if (!getLangOpts().CPlusPlus) return false; if (const ArrayType *AT = Context.getAsArrayType(T)) return RequireNonAbstractType(Loc, AT->getElementType(), PD); if (const PointerType *PT = T->getAs()) { // Find the innermost pointer type. while (const PointerType *T = PT->getPointeeType()->getAs()) PT = T; if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType())) return RequireNonAbstractType(Loc, AT->getElementType(), PD); } const RecordType *RT = T->getAs(); if (!RT) return false; const CXXRecordDecl *RD = cast(RT->getDecl()); // We can't answer whether something is abstract until it has a // definition. If it's currently being defined, we'll walk back // over all the declarations when we have a full definition. const CXXRecordDecl *Def = RD->getDefinition(); if (!Def || Def->isBeingDefined()) return false; if (!RD->isAbstract()) return false; Diag(Loc, PD) << RD->getDeclName(); DiagnoseAbstractType(RD); return true; } void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) { // Check if we've already emitted the list of pure virtual functions // for this class. if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD)) return; CXXFinalOverriderMap FinalOverriders; RD->getFinalOverriders(FinalOverriders); // Keep a set of seen pure methods so we won't diagnose the same method // more than once. llvm::SmallPtrSet SeenPureMethods; 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) { // C++ [class.abstract]p4: // A class is abstract if it contains or inherits at least one // pure virtual function for which the final overrider is pure // virtual. // if (SO->second.size() != 1) continue; if (!SO->second.front().Method->isPure()) continue; if (!SeenPureMethods.insert(SO->second.front().Method)) continue; Diag(SO->second.front().Method->getLocation(), diag::note_pure_virtual_function) << SO->second.front().Method->getDeclName() << RD->getDeclName(); } } if (!PureVirtualClassDiagSet) PureVirtualClassDiagSet.reset(new RecordDeclSetTy); PureVirtualClassDiagSet->insert(RD); } namespace { struct AbstractUsageInfo { Sema &S; CXXRecordDecl *Record; CanQualType AbstractType; bool Invalid; AbstractUsageInfo(Sema &S, CXXRecordDecl *Record) : S(S), Record(Record), AbstractType(S.Context.getCanonicalType( S.Context.getTypeDeclType(Record))), Invalid(false) {} void DiagnoseAbstractType() { if (Invalid) return; S.DiagnoseAbstractType(Record); Invalid = true; } void CheckType(const NamedDecl *D, TypeLoc TL, Sema::AbstractDiagSelID Sel); }; struct CheckAbstractUsage { AbstractUsageInfo &Info; const NamedDecl *Ctx; CheckAbstractUsage(AbstractUsageInfo &Info, const NamedDecl *Ctx) : Info(Info), Ctx(Ctx) {} void Visit(TypeLoc TL, Sema::AbstractDiagSelID Sel) { switch (TL.getTypeLocClass()) { #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ case TypeLoc::CLASS: Check(cast(TL), Sel); break; #include "clang/AST/TypeLocNodes.def" } } void Check(FunctionProtoTypeLoc TL, Sema::AbstractDiagSelID Sel) { Visit(TL.getResultLoc(), Sema::AbstractReturnType); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { if (!TL.getArg(I)) continue; TypeSourceInfo *TSI = TL.getArg(I)->getTypeSourceInfo(); if (TSI) Visit(TSI->getTypeLoc(), Sema::AbstractParamType); } } void Check(ArrayTypeLoc TL, Sema::AbstractDiagSelID Sel) { Visit(TL.getElementLoc(), Sema::AbstractArrayType); } void Check(TemplateSpecializationTypeLoc TL, Sema::AbstractDiagSelID Sel) { // Visit the type parameters from a permissive context. for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { TemplateArgumentLoc TAL = TL.getArgLoc(I); if (TAL.getArgument().getKind() == TemplateArgument::Type) if (TypeSourceInfo *TSI = TAL.getTypeSourceInfo()) Visit(TSI->getTypeLoc(), Sema::AbstractNone); // TODO: other template argument types? } } // Visit pointee types from a permissive context. #define CheckPolymorphic(Type) \ void Check(Type TL, Sema::AbstractDiagSelID Sel) { \ Visit(TL.getNextTypeLoc(), Sema::AbstractNone); \ } CheckPolymorphic(PointerTypeLoc) CheckPolymorphic(ReferenceTypeLoc) CheckPolymorphic(MemberPointerTypeLoc) CheckPolymorphic(BlockPointerTypeLoc) CheckPolymorphic(AtomicTypeLoc) /// Handle all the types we haven't given a more specific /// implementation for above. void Check(TypeLoc TL, Sema::AbstractDiagSelID Sel) { // Every other kind of type that we haven't called out already // that has an inner type is either (1) sugar or (2) contains that // inner type in some way as a subobject. if (TypeLoc Next = TL.getNextTypeLoc()) return Visit(Next, Sel); // If there's no inner type and we're in a permissive context, // don't diagnose. if (Sel == Sema::AbstractNone) return; // Check whether the type matches the abstract type. QualType T = TL.getType(); if (T->isArrayType()) { Sel = Sema::AbstractArrayType; T = Info.S.Context.getBaseElementType(T); } CanQualType CT = T->getCanonicalTypeUnqualified().getUnqualifiedType(); if (CT != Info.AbstractType) return; // It matched; do some magic. if (Sel == Sema::AbstractArrayType) { Info.S.Diag(Ctx->getLocation(), diag::err_array_of_abstract_type) << T << TL.getSourceRange(); } else { Info.S.Diag(Ctx->getLocation(), diag::err_abstract_type_in_decl) << Sel << T << TL.getSourceRange(); } Info.DiagnoseAbstractType(); } }; void AbstractUsageInfo::CheckType(const NamedDecl *D, TypeLoc TL, Sema::AbstractDiagSelID Sel) { CheckAbstractUsage(*this, D).Visit(TL, Sel); } } /// Check for invalid uses of an abstract type in a method declaration. static void CheckAbstractClassUsage(AbstractUsageInfo &Info, CXXMethodDecl *MD) { // No need to do the check on definitions, which require that // the return/param types be complete. if (MD->doesThisDeclarationHaveABody()) return; // For safety's sake, just ignore it if we don't have type source // information. This should never happen for non-implicit methods, // but... if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) Info.CheckType(MD, TSI->getTypeLoc(), Sema::AbstractNone); } /// Check for invalid uses of an abstract type within a class definition. static void CheckAbstractClassUsage(AbstractUsageInfo &Info, CXXRecordDecl *RD) { for (CXXRecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end(); I != E; ++I) { Decl *D = *I; if (D->isImplicit()) continue; // Methods and method templates. if (isa(D)) { CheckAbstractClassUsage(Info, cast(D)); } else if (isa(D)) { FunctionDecl *FD = cast(D)->getTemplatedDecl(); CheckAbstractClassUsage(Info, cast(FD)); // Fields and static variables. } else if (isa(D)) { FieldDecl *FD = cast(D); if (TypeSourceInfo *TSI = FD->getTypeSourceInfo()) Info.CheckType(FD, TSI->getTypeLoc(), Sema::AbstractFieldType); } else if (isa(D)) { VarDecl *VD = cast(D); if (TypeSourceInfo *TSI = VD->getTypeSourceInfo()) Info.CheckType(VD, TSI->getTypeLoc(), Sema::AbstractVariableType); // Nested classes and class templates. } else if (isa(D)) { CheckAbstractClassUsage(Info, cast(D)); } else if (isa(D)) { CheckAbstractClassUsage(Info, cast(D)->getTemplatedDecl()); } } } /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (!Record) return; if (Record->isAbstract() && !Record->isInvalidDecl()) { AbstractUsageInfo Info(*this, Record); CheckAbstractClassUsage(Info, Record); } // If this is not an aggregate type and has no user-declared constructor, // complain about any non-static data members of reference or const scalar // type, since they will never get initializers. if (!Record->isInvalidDecl() && !Record->isDependentType() && !Record->isAggregate() && !Record->hasUserDeclaredConstructor() && !Record->isLambda()) { bool Complained = false; for (RecordDecl::field_iterator F = Record->field_begin(), FEnd = Record->field_end(); F != FEnd; ++F) { if (F->hasInClassInitializer() || F->isUnnamedBitfield()) continue; if (F->getType()->isReferenceType() || (F->getType().isConstQualified() && F->getType()->isScalarType())) { if (!Complained) { Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst) << Record->getTagKind() << Record; Complained = true; } Diag(F->getLocation(), diag::note_refconst_member_not_initialized) << F->getType()->isReferenceType() << F->getDeclName(); } } } if (Record->isDynamicClass() && !Record->isDependentType()) DynamicClasses.push_back(Record); if (Record->getIdentifier()) { // 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 member of every anonymous union that is a member of class T. // // C++ [class.mem]p14: // In addition, if class T has a user-declared constructor (12.1), every // non-static data member of class T shall have a name different from T. for (DeclContext::lookup_result R = Record->lookup(Record->getDeclName()); R.first != R.second; ++R.first) { NamedDecl *D = *R.first; if ((isa(D) && Record->hasUserDeclaredConstructor()) || isa(D)) { Diag(D->getLocation(), diag::err_member_name_of_class) << D->getDeclName(); break; } } } // Warn if the class has virtual methods but non-virtual public destructor. if (Record->isPolymorphic() && !Record->isDependentType()) { CXXDestructorDecl *dtor = Record->getDestructor(); if (!dtor || (!dtor->isVirtual() && dtor->getAccess() == AS_public)) Diag(dtor ? dtor->getLocation() : Record->getLocation(), diag::warn_non_virtual_dtor) << Context.getRecordType(Record); } // See if a method overloads virtual methods in a base /// class without overriding any. if (!Record->isDependentType()) { for (CXXRecordDecl::method_iterator M = Record->method_begin(), MEnd = Record->method_end(); M != MEnd; ++M) { if (!(*M)->isStatic()) DiagnoseHiddenVirtualMethods(Record, *M); } } // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member // function that is not a constructor declares that member function to be // const. [...] The class of which that function is a member shall be // a literal type. // // If the class has virtual bases, any constexpr members will already have // been diagnosed by the checks performed on the member declaration, so // suppress this (less useful) diagnostic. if (LangOpts.CPlusPlus0x && !Record->isDependentType() && !Record->isLiteral() && !Record->getNumVBases()) { for (CXXRecordDecl::method_iterator M = Record->method_begin(), MEnd = Record->method_end(); M != MEnd; ++M) { if (M->isConstexpr() && M->isInstance() && !isa(*M)) { switch (Record->getTemplateSpecializationKind()) { case TSK_ImplicitInstantiation: case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: // If a template instantiates to a non-literal type, but its members // instantiate to constexpr functions, the template is technically // ill-formed, but we allow it for sanity. continue; case TSK_Undeclared: case TSK_ExplicitSpecialization: RequireLiteralType((*M)->getLocation(), Context.getRecordType(Record), PDiag(diag::err_constexpr_method_non_literal)); break; } // Only produce one error per class. break; } } } // Declare inherited constructors. We do this eagerly here because: // - The standard requires an eager diagnostic for conflicting inherited // constructors from different classes. // - The lazy declaration of the other implicit constructors is so as to not // waste space and performance on classes that are not meant to be // instantiated (e.g. meta-functions). This doesn't apply to classes that // have inherited constructors. DeclareInheritedConstructors(Record); if (!Record->isDependentType()) CheckExplicitlyDefaultedMethods(Record); } void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) { for (CXXRecordDecl::method_iterator MI = Record->method_begin(), ME = Record->method_end(); MI != ME; ++MI) { if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) { switch (getSpecialMember(*MI)) { case CXXDefaultConstructor: CheckExplicitlyDefaultedDefaultConstructor( cast(*MI)); break; case CXXDestructor: CheckExplicitlyDefaultedDestructor(cast(*MI)); break; case CXXCopyConstructor: CheckExplicitlyDefaultedCopyConstructor(cast(*MI)); break; case CXXCopyAssignment: CheckExplicitlyDefaultedCopyAssignment(*MI); break; case CXXMoveConstructor: CheckExplicitlyDefaultedMoveConstructor(cast(*MI)); break; case CXXMoveAssignment: CheckExplicitlyDefaultedMoveAssignment(*MI); break; case CXXInvalid: llvm_unreachable("non-special member explicitly defaulted!"); } } } } void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { assert(CD->isExplicitlyDefaulted() && CD->isDefaultConstructor()); // Whether this was the first-declared instance of the constructor. // This affects whether we implicitly add an exception spec (and, eventually, // constexpr). It is also ill-formed to explicitly default a constructor such // that it would be deleted. (C++0x [decl.fct.def.default]) bool First = CD == CD->getCanonicalDecl(); bool HadError = false; if (CD->getNumParams() != 0) { Diag(CD->getLocation(), diag::err_defaulted_default_ctor_params) << CD->getSourceRange(); HadError = true; } ImplicitExceptionSpecification Spec = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent()); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); if (EPI.ExceptionSpecType == EST_Delayed) { // Exception specification depends on some deferred part of the class. We'll // try again when the class's definition has been fully processed. return; } const FunctionProtoType *CtorType = CD->getType()->getAs(), *ExceptionType = Context.getFunctionType( Context.VoidTy, 0, 0, EPI)->getAs(); // C++11 [dcl.fct.def.default]p2: // An explicitly-defaulted function may be declared constexpr only if it // would have been implicitly declared as constexpr, // Do not apply this rule to templates, since core issue 1358 makes such // functions always instantiate to constexpr functions. if (CD->isConstexpr() && CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { if (!CD->getParent()->defaultedDefaultConstructorIsConstexpr()) { Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CXXDefaultConstructor; HadError = true; } } // and may have an explicit exception-specification only if it is compatible // with the exception-specification on the implicit declaration. if (CtorType->hasExceptionSpec()) { if (CheckEquivalentExceptionSpec( PDiag(diag::err_incorrect_defaulted_exception_spec) << CXXDefaultConstructor, PDiag(), ExceptionType, SourceLocation(), CtorType, CD->getLocation())) { HadError = true; } } // If a function is explicitly defaulted on its first declaration, if (First) { // -- it is implicitly considered to be constexpr if the implicit // definition would be, CD->setConstexpr(CD->getParent()->defaultedDefaultConstructorIsConstexpr()); // -- it is implicitly considered to have the same // exception-specification as if it had been implicitly declared // // FIXME: a compatible, but different, explicit exception specification // will be silently overridden. We should issue a warning if this happens. EPI.ExtInfo = CtorType->getExtInfo(); // Such a function is also trivial if the implicitly-declared function // would have been. CD->setTrivial(CD->getParent()->hasTrivialDefaultConstructor()); } if (HadError) { CD->setInvalidDecl(); return; } if (ShouldDeleteSpecialMember(CD, CXXDefaultConstructor)) { if (First) { CD->setDeletedAsWritten(); } else { Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) << CXXDefaultConstructor; CD->setInvalidDecl(); } } } void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { assert(CD->isExplicitlyDefaulted() && CD->isCopyConstructor()); // Whether this was the first-declared instance of the constructor. bool First = CD == CD->getCanonicalDecl(); bool HadError = false; if (CD->getNumParams() != 1) { Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_params) << CD->getSourceRange(); HadError = true; } ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent()); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); const FunctionProtoType *CtorType = CD->getType()->getAs(), *ExceptionType = Context.getFunctionType( Context.VoidTy, 0, 0, EPI)->getAs(); // Check for parameter type matching. // This is a copy ctor so we know it's a cv-qualified reference to T. QualType ArgType = CtorType->getArgType(0); if (ArgType->getPointeeType().isVolatileQualified()) { Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_volatile_param); HadError = true; } if (ArgType->getPointeeType().isConstQualified() && !Const) { Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_const_param); HadError = true; } // C++11 [dcl.fct.def.default]p2: // An explicitly-defaulted function may be declared constexpr only if it // would have been implicitly declared as constexpr, // Do not apply this rule to templates, since core issue 1358 makes such // functions always instantiate to constexpr functions. if (CD->isConstexpr() && CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { if (!CD->getParent()->defaultedCopyConstructorIsConstexpr()) { Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CXXCopyConstructor; HadError = true; } } // and may have an explicit exception-specification only if it is compatible // with the exception-specification on the implicit declaration. if (CtorType->hasExceptionSpec()) { if (CheckEquivalentExceptionSpec( PDiag(diag::err_incorrect_defaulted_exception_spec) << CXXCopyConstructor, PDiag(), ExceptionType, SourceLocation(), CtorType, CD->getLocation())) { HadError = true; } } // If a function is explicitly defaulted on its first declaration, if (First) { // -- it is implicitly considered to be constexpr if the implicit // definition would be, CD->setConstexpr(CD->getParent()->defaultedCopyConstructorIsConstexpr()); // -- it is implicitly considered to have the same // exception-specification as if it had been implicitly declared, and // // FIXME: a compatible, but different, explicit exception specification // will be silently overridden. We should issue a warning if this happens. EPI.ExtInfo = CtorType->getExtInfo(); // -- [...] it shall have the same parameter type as if it had been // implicitly declared. CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); // Such a function is also trivial if the implicitly-declared function // would have been. CD->setTrivial(CD->getParent()->hasTrivialCopyConstructor()); } if (HadError) { CD->setInvalidDecl(); return; } if (ShouldDeleteSpecialMember(CD, CXXCopyConstructor)) { if (First) { CD->setDeletedAsWritten(); } else { Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) << CXXCopyConstructor; CD->setInvalidDecl(); } } } void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { assert(MD->isExplicitlyDefaulted()); // Whether this was the first-declared instance of the operator bool First = MD == MD->getCanonicalDecl(); bool HadError = false; if (MD->getNumParams() != 1) { Diag(MD->getLocation(), diag::err_defaulted_copy_assign_params) << MD->getSourceRange(); HadError = true; } QualType ReturnType = MD->getType()->getAs()->getResultType(); if (!ReturnType->isLValueReferenceType() || !Context.hasSameType( Context.getCanonicalType(ReturnType->getPointeeType()), Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) { Diag(MD->getLocation(), diag::err_defaulted_copy_assign_return_type); HadError = true; } ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent()); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); const FunctionProtoType *OperType = MD->getType()->getAs(), *ExceptionType = Context.getFunctionType( Context.VoidTy, 0, 0, EPI)->getAs(); QualType ArgType = OperType->getArgType(0); if (!ArgType->isLValueReferenceType()) { Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref); HadError = true; } else { if (ArgType->getPointeeType().isVolatileQualified()) { Diag(MD->getLocation(), diag::err_defaulted_copy_assign_volatile_param); HadError = true; } if (ArgType->getPointeeType().isConstQualified() && !Const) { Diag(MD->getLocation(), diag::err_defaulted_copy_assign_const_param); HadError = true; } } if (OperType->getTypeQuals()) { Diag(MD->getLocation(), diag::err_defaulted_copy_assign_quals); HadError = true; } if (OperType->hasExceptionSpec()) { if (CheckEquivalentExceptionSpec( PDiag(diag::err_incorrect_defaulted_exception_spec) << CXXCopyAssignment, PDiag(), ExceptionType, SourceLocation(), OperType, MD->getLocation())) { HadError = true; } } if (First) { // We set the declaration to have the computed exception spec here. // We duplicate the one parameter type. EPI.RefQualifier = OperType->getRefQualifier(); EPI.ExtInfo = OperType->getExtInfo(); MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); // Such a function is also trivial if the implicitly-declared function // would have been. MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment()); } if (HadError) { MD->setInvalidDecl(); return; } if (ShouldDeleteSpecialMember(MD, CXXCopyAssignment)) { if (First) { MD->setDeletedAsWritten(); } else { Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CXXCopyAssignment; MD->setInvalidDecl(); } } } void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) { assert(CD->isExplicitlyDefaulted() && CD->isMoveConstructor()); // Whether this was the first-declared instance of the constructor. bool First = CD == CD->getCanonicalDecl(); bool HadError = false; if (CD->getNumParams() != 1) { Diag(CD->getLocation(), diag::err_defaulted_move_ctor_params) << CD->getSourceRange(); HadError = true; } ImplicitExceptionSpecification Spec( ComputeDefaultedMoveCtorExceptionSpec(CD->getParent())); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); const FunctionProtoType *CtorType = CD->getType()->getAs(), *ExceptionType = Context.getFunctionType( Context.VoidTy, 0, 0, EPI)->getAs(); // Check for parameter type matching. // This is a move ctor so we know it's a cv-qualified rvalue reference to T. QualType ArgType = CtorType->getArgType(0); if (ArgType->getPointeeType().isVolatileQualified()) { Diag(CD->getLocation(), diag::err_defaulted_move_ctor_volatile_param); HadError = true; } if (ArgType->getPointeeType().isConstQualified()) { Diag(CD->getLocation(), diag::err_defaulted_move_ctor_const_param); HadError = true; } // C++11 [dcl.fct.def.default]p2: // An explicitly-defaulted function may be declared constexpr only if it // would have been implicitly declared as constexpr, // Do not apply this rule to templates, since core issue 1358 makes such // functions always instantiate to constexpr functions. if (CD->isConstexpr() && CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { if (!CD->getParent()->defaultedMoveConstructorIsConstexpr()) { Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CXXMoveConstructor; HadError = true; } } // and may have an explicit exception-specification only if it is compatible // with the exception-specification on the implicit declaration. if (CtorType->hasExceptionSpec()) { if (CheckEquivalentExceptionSpec( PDiag(diag::err_incorrect_defaulted_exception_spec) << CXXMoveConstructor, PDiag(), ExceptionType, SourceLocation(), CtorType, CD->getLocation())) { HadError = true; } } // If a function is explicitly defaulted on its first declaration, if (First) { // -- it is implicitly considered to be constexpr if the implicit // definition would be, CD->setConstexpr(CD->getParent()->defaultedMoveConstructorIsConstexpr()); // -- it is implicitly considered to have the same // exception-specification as if it had been implicitly declared, and // // FIXME: a compatible, but different, explicit exception specification // will be silently overridden. We should issue a warning if this happens. EPI.ExtInfo = CtorType->getExtInfo(); // -- [...] it shall have the same parameter type as if it had been // implicitly declared. CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); // Such a function is also trivial if the implicitly-declared function // would have been. CD->setTrivial(CD->getParent()->hasTrivialMoveConstructor()); } if (HadError) { CD->setInvalidDecl(); return; } if (ShouldDeleteSpecialMember(CD, CXXMoveConstructor)) { if (First) { CD->setDeletedAsWritten(); } else { Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) << CXXMoveConstructor; CD->setInvalidDecl(); } } } void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) { assert(MD->isExplicitlyDefaulted()); // Whether this was the first-declared instance of the operator bool First = MD == MD->getCanonicalDecl(); bool HadError = false; if (MD->getNumParams() != 1) { Diag(MD->getLocation(), diag::err_defaulted_move_assign_params) << MD->getSourceRange(); HadError = true; } QualType ReturnType = MD->getType()->getAs()->getResultType(); if (!ReturnType->isLValueReferenceType() || !Context.hasSameType( Context.getCanonicalType(ReturnType->getPointeeType()), Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) { Diag(MD->getLocation(), diag::err_defaulted_move_assign_return_type); HadError = true; } ImplicitExceptionSpecification Spec( ComputeDefaultedMoveCtorExceptionSpec(MD->getParent())); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); const FunctionProtoType *OperType = MD->getType()->getAs(), *ExceptionType = Context.getFunctionType( Context.VoidTy, 0, 0, EPI)->getAs(); QualType ArgType = OperType->getArgType(0); if (!ArgType->isRValueReferenceType()) { Diag(MD->getLocation(), diag::err_defaulted_move_assign_not_ref); HadError = true; } else { if (ArgType->getPointeeType().isVolatileQualified()) { Diag(MD->getLocation(), diag::err_defaulted_move_assign_volatile_param); HadError = true; } if (ArgType->getPointeeType().isConstQualified()) { Diag(MD->getLocation(), diag::err_defaulted_move_assign_const_param); HadError = true; } } if (OperType->getTypeQuals()) { Diag(MD->getLocation(), diag::err_defaulted_move_assign_quals); HadError = true; } if (OperType->hasExceptionSpec()) { if (CheckEquivalentExceptionSpec( PDiag(diag::err_incorrect_defaulted_exception_spec) << CXXMoveAssignment, PDiag(), ExceptionType, SourceLocation(), OperType, MD->getLocation())) { HadError = true; } } if (First) { // We set the declaration to have the computed exception spec here. // We duplicate the one parameter type. EPI.RefQualifier = OperType->getRefQualifier(); EPI.ExtInfo = OperType->getExtInfo(); MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); // Such a function is also trivial if the implicitly-declared function // would have been. MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment()); } if (HadError) { MD->setInvalidDecl(); return; } if (ShouldDeleteSpecialMember(MD, CXXMoveAssignment)) { if (First) { MD->setDeletedAsWritten(); } else { Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CXXMoveAssignment; MD->setInvalidDecl(); } } } void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { assert(DD->isExplicitlyDefaulted()); // Whether this was the first-declared instance of the destructor. bool First = DD == DD->getCanonicalDecl(); ImplicitExceptionSpecification Spec = ComputeDefaultedDtorExceptionSpec(DD->getParent()); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); const FunctionProtoType *DtorType = DD->getType()->getAs(), *ExceptionType = Context.getFunctionType( Context.VoidTy, 0, 0, EPI)->getAs(); if (DtorType->hasExceptionSpec()) { if (CheckEquivalentExceptionSpec( PDiag(diag::err_incorrect_defaulted_exception_spec) << CXXDestructor, PDiag(), ExceptionType, SourceLocation(), DtorType, DD->getLocation())) { DD->setInvalidDecl(); return; } } if (First) { // We set the declaration to have the computed exception spec here. // There are no parameters. EPI.ExtInfo = DtorType->getExtInfo(); DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); // Such a function is also trivial if the implicitly-declared function // would have been. DD->setTrivial(DD->getParent()->hasTrivialDestructor()); } if (ShouldDeleteSpecialMember(DD, CXXDestructor)) { if (First) { DD->setDeletedAsWritten(); } else { Diag(DD->getLocation(), diag::err_out_of_line_default_deletes) << CXXDestructor; DD->setInvalidDecl(); } } } namespace { struct SpecialMemberDeletionInfo { Sema &S; CXXMethodDecl *MD; Sema::CXXSpecialMember CSM; bool Diagnose; // Properties of the special member, computed for convenience. bool IsConstructor, IsAssignment, IsMove, ConstArg, VolatileArg; SourceLocation Loc; bool AllFieldsAreConst; SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM, bool Diagnose) : S(S), MD(MD), CSM(CSM), Diagnose(Diagnose), IsConstructor(false), IsAssignment(false), IsMove(false), ConstArg(false), VolatileArg(false), Loc(MD->getLocation()), AllFieldsAreConst(true) { switch (CSM) { case Sema::CXXDefaultConstructor: case Sema::CXXCopyConstructor: IsConstructor = true; break; case Sema::CXXMoveConstructor: IsConstructor = true; IsMove = true; break; case Sema::CXXCopyAssignment: IsAssignment = true; break; case Sema::CXXMoveAssignment: IsAssignment = true; IsMove = true; break; case Sema::CXXDestructor: break; case Sema::CXXInvalid: llvm_unreachable("invalid special member kind"); } if (MD->getNumParams()) { ConstArg = MD->getParamDecl(0)->getType().isConstQualified(); VolatileArg = MD->getParamDecl(0)->getType().isVolatileQualified(); } } bool inUnion() const { return MD->getParent()->isUnion(); } /// Look up the corresponding special member in the given class. Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class) { unsigned TQ = MD->getTypeQualifiers(); return S.LookupSpecialMember(Class, CSM, ConstArg, VolatileArg, MD->getRefQualifier() == RQ_RValue, TQ & Qualifiers::Const, TQ & Qualifiers::Volatile); } typedef llvm::PointerUnion Subobject; bool shouldDeleteForBase(CXXBaseSpecifier *Base); bool shouldDeleteForField(FieldDecl *FD); bool shouldDeleteForAllConstMembers(); bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj); bool shouldDeleteForSubobjectCall(Subobject Subobj, Sema::SpecialMemberOverloadResult *SMOR, bool IsDtorCallInCtor); bool isAccessible(Subobject Subobj, CXXMethodDecl *D); }; } /// Is the given special member inaccessible when used on the given /// sub-object. bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj, CXXMethodDecl *target) { /// If we're operating on a base class, the object type is the /// type of this special member. QualType objectTy; AccessSpecifier access = target->getAccess();; if (CXXBaseSpecifier *base = Subobj.dyn_cast()) { objectTy = S.Context.getTypeDeclType(MD->getParent()); access = CXXRecordDecl::MergeAccess(base->getAccessSpecifier(), access); // If we're operating on a field, the object type is the type of the field. } else { objectTy = S.Context.getTypeDeclType(target->getParent()); } return S.isSpecialMemberAccessibleForDeletion(target, access, objectTy); } /// Check whether we should delete a special member due to the implicit /// definition containing a call to a special member of a subobject. bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( Subobject Subobj, Sema::SpecialMemberOverloadResult *SMOR, bool IsDtorCallInCtor) { CXXMethodDecl *Decl = SMOR->getMethod(); FieldDecl *Field = Subobj.dyn_cast(); int DiagKind = -1; if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted) DiagKind = !Decl ? 0 : 1; else if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous) DiagKind = 2; else if (!isAccessible(Subobj, Decl)) DiagKind = 3; else if (!IsDtorCallInCtor && Field && Field->getParent()->isUnion() && !Decl->isTrivial()) { // A member of a union must have a trivial corresponding special member. // As a weird special case, a destructor call from a union's constructor // must be accessible and non-deleted, but need not be trivial. Such a // destructor is never actually called, but is semantically checked as // if it were. DiagKind = 4; } if (DiagKind == -1) return false; if (Diagnose) { if (Field) { S.Diag(Field->getLocation(), diag::note_deleted_special_member_class_subobject) << CSM << MD->getParent() << /*IsField*/true << Field << DiagKind << IsDtorCallInCtor; } else { CXXBaseSpecifier *Base = Subobj.get(); S.Diag(Base->getLocStart(), diag::note_deleted_special_member_class_subobject) << CSM << MD->getParent() << /*IsField*/false << Base->getType() << DiagKind << IsDtorCallInCtor; } if (DiagKind == 1) S.NoteDeletedFunction(Decl); // FIXME: Explain inaccessibility if DiagKind == 3. } return true; } /// Check whether we should delete a special member function due to having a /// direct or virtual base class or static data member of class type M. bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( CXXRecordDecl *Class, Subobject Subobj) { FieldDecl *Field = Subobj.dyn_cast(); // C++11 [class.ctor]p5: // -- any direct or virtual base class, or non-static data member with no // brace-or-equal-initializer, has class type M (or array thereof) and // either M has no default constructor or overload resolution as applied // to M's default constructor results in an ambiguity or in a function // that is deleted or inaccessible // C++11 [class.copy]p11, C++11 [class.copy]p23: // -- a direct or virtual base class B that cannot be copied/moved because // overload resolution, as applied to B's corresponding special member, // results in an ambiguity or a function that is deleted or inaccessible // from the defaulted special member // C++11 [class.dtor]p5: // -- any direct or virtual base class [...] has a type with a destructor // that is deleted or inaccessible if (!(CSM == Sema::CXXDefaultConstructor && Field && Field->hasInClassInitializer()) && shouldDeleteForSubobjectCall(Subobj, lookupIn(Class), false)) return true; // C++11 [class.ctor]p5, C++11 [class.copy]p11: // -- any direct or virtual base class or non-static data member has a // type with a destructor that is deleted or inaccessible if (IsConstructor) { Sema::SpecialMemberOverloadResult *SMOR = S.LookupSpecialMember(Class, Sema::CXXDestructor, false, false, false, false, false); if (shouldDeleteForSubobjectCall(Subobj, SMOR, true)) return true; } return false; } /// Check whether we should delete a special member function due to the class /// having a particular direct or virtual base class. bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl(); return shouldDeleteForClassSubobject(BaseClass, Base); } /// Check whether we should delete a special member function due to the class /// having a particular non-static data member. bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { QualType FieldType = S.Context.getBaseElementType(FD->getType()); CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); if (CSM == Sema::CXXDefaultConstructor) { // For a default constructor, all references must be initialized in-class // and, if a union, it must have a non-const member. if (FieldType->isReferenceType() && !FD->hasInClassInitializer()) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) << MD->getParent() << FD << FieldType << /*Reference*/0; return true; } // C++11 [class.ctor]p5: any non-variant non-static data member of // const-qualified type (or array thereof) with no // brace-or-equal-initializer does not have a user-provided default // constructor. if (!inUnion() && FieldType.isConstQualified() && !FD->hasInClassInitializer() && (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) << MD->getParent() << FD << FieldType << /*Const*/1; return true; } if (inUnion() && !FieldType.isConstQualified()) AllFieldsAreConst = false; } else if (CSM == Sema::CXXCopyConstructor) { // For a copy constructor, data members must not be of rvalue reference // type. if (FieldType->isRValueReferenceType()) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_copy_ctor_rvalue_reference) << MD->getParent() << FD << FieldType; return true; } } else if (IsAssignment) { // For an assignment operator, data members must not be of reference type. if (FieldType->isReferenceType()) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_assign_field) << IsMove << MD->getParent() << FD << FieldType << /*Reference*/0; return true; } if (!FieldRecord && FieldType.isConstQualified()) { // C++11 [class.copy]p23: // -- a non-static data member of const non-class type (or array thereof) if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_assign_field) << IsMove << MD->getParent() << FD << FieldType << /*Const*/1; return true; } } if (FieldRecord) { // Some additional restrictions exist on the variant members. if (!inUnion() && FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { bool AllVariantFieldsAreConst = true; // FIXME: Handle anonymous unions declared within anonymous unions. for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(), UE = FieldRecord->field_end(); UI != UE; ++UI) { QualType UnionFieldType = S.Context.getBaseElementType(UI->getType()); if (!UnionFieldType.isConstQualified()) AllVariantFieldsAreConst = false; CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl(); if (UnionFieldRecord && shouldDeleteForClassSubobject(UnionFieldRecord, *UI)) return true; } // At least one member in each anonymous union must be non-const if (CSM == Sema::CXXDefaultConstructor && AllVariantFieldsAreConst && FieldRecord->field_begin() != FieldRecord->field_end()) { if (Diagnose) S.Diag(FieldRecord->getLocation(), diag::note_deleted_default_ctor_all_const) << MD->getParent() << /*anonymous union*/1; return true; } // Don't check the implicit member of the anonymous union type. // This is technically non-conformant, but sanity demands it. return false; } if (shouldDeleteForClassSubobject(FieldRecord, FD)) return true; } return false; } /// C++11 [class.ctor] p5: /// A defaulted default constructor for a class X is defined as deleted if /// X is a union and all of its variant members are of const-qualified type. bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() { // This is a silly definition, because it gives an empty union a deleted // default constructor. Don't do that. if (CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst && (MD->getParent()->field_begin() != MD->getParent()->field_end())) { if (Diagnose) S.Diag(MD->getParent()->getLocation(), diag::note_deleted_default_ctor_all_const) << MD->getParent() << /*not anonymous union*/0; return true; } return false; } /// Determine whether a defaulted special member function should be defined as /// deleted, as specified in C++11 [class.ctor]p5, C++11 [class.copy]p11, /// C++11 [class.copy]p23, and C++11 [class.dtor]p5. bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, bool Diagnose) { assert(!MD->isInvalidDecl()); CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; // C++11 [expr.lambda.prim]p19: // The closure type associated with a lambda-expression has a // deleted (8.4.3) default constructor and a deleted copy // assignment operator. if (RD->isLambda() && (CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment)) { if (Diagnose) Diag(RD->getLocation(), diag::note_lambda_decl); return true; } // For an anonymous struct or union, the copy and assignment special members // will never be used, so skip the check. For an anonymous union declared at // namespace scope, the constructor and destructor are used. if (CSM != CXXDefaultConstructor && CSM != CXXDestructor && RD->isAnonymousStructOrUnion()) return false; // C++11 [class.copy]p7, p18: // If the class definition declares a move constructor or move assignment // operator, an implicitly declared copy constructor or copy assignment // operator is defined as deleted. if (MD->isImplicit() && (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)) { CXXMethodDecl *UserDeclaredMove = 0; // In Microsoft mode, a user-declared move only causes the deletion of the // corresponding copy operation, not both copy operations. if (RD->hasUserDeclaredMoveConstructor() && (!getLangOpts().MicrosoftMode || CSM == CXXCopyConstructor)) { if (!Diagnose) return true; UserDeclaredMove = RD->getMoveConstructor(); assert(UserDeclaredMove); } else if (RD->hasUserDeclaredMoveAssignment() && (!getLangOpts().MicrosoftMode || CSM == CXXCopyAssignment)) { if (!Diagnose) return true; UserDeclaredMove = RD->getMoveAssignmentOperator(); assert(UserDeclaredMove); } if (UserDeclaredMove) { Diag(UserDeclaredMove->getLocation(), diag::note_deleted_copy_user_declared_move) << (CSM == CXXCopyAssignment) << RD << UserDeclaredMove->isMoveAssignmentOperator(); return true; } } // Do access control from the special member function ContextRAII MethodContext(*this, MD); // C++11 [class.dtor]p5: // -- for a virtual destructor, lookup of the non-array deallocation function // results in an ambiguity or in a function that is deleted or inaccessible if (CSM == CXXDestructor && MD->isVirtual()) { FunctionDecl *OperatorDelete = 0; DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); if (FindDeallocationFunction(MD->getLocation(), MD->getParent(), Name, OperatorDelete, false)) { if (Diagnose) Diag(RD->getLocation(), diag::note_deleted_dtor_no_operator_delete); return true; } } SpecialMemberDeletionInfo SMI(*this, MD, CSM, Diagnose); for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), BE = RD->bases_end(); BI != BE; ++BI) if (!BI->isVirtual() && SMI.shouldDeleteForBase(BI)) return true; for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), BE = RD->vbases_end(); BI != BE; ++BI) if (SMI.shouldDeleteForBase(BI)) return true; for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) if (!FI->isInvalidDecl() && !FI->isUnnamedBitfield() && SMI.shouldDeleteForField(*FI)) return true; if (SMI.shouldDeleteForAllConstMembers()) return true; return false; } /// \brief Data used with FindHiddenVirtualMethod namespace { struct FindHiddenVirtualMethodData { Sema *S; CXXMethodDecl *Method; llvm::SmallPtrSet OverridenAndUsingBaseMethods; SmallVector OverloadedMethods; }; } /// \brief Member lookup function that determines whether a given C++ /// method overloads virtual methods in a base class without overriding any, /// to be used with CXXRecordDecl::lookupInBases(). static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *UserData) { RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); FindHiddenVirtualMethodData &Data = *static_cast(UserData); DeclarationName Name = Data.Method->getDeclName(); assert(Name.getNameKind() == DeclarationName::Identifier); bool foundSameNameMethod = false; SmallVector overloadedMethods; for (Path.Decls = BaseRecord->lookup(Name); Path.Decls.first != Path.Decls.second; ++Path.Decls.first) { NamedDecl *D = *Path.Decls.first; if (CXXMethodDecl *MD = dyn_cast(D)) { MD = MD->getCanonicalDecl(); foundSameNameMethod = true; // Interested only in hidden virtual methods. if (!MD->isVirtual()) continue; // If the method we are checking overrides a method from its base // don't warn about the other overloaded methods. if (!Data.S->IsOverload(Data.Method, MD, false)) return true; // Collect the overload only if its hidden. if (!Data.OverridenAndUsingBaseMethods.count(MD)) overloadedMethods.push_back(MD); } } if (foundSameNameMethod) Data.OverloadedMethods.append(overloadedMethods.begin(), overloadedMethods.end()); return foundSameNameMethod; } /// \brief See if a method overloads virtual methods in a base class without /// overriding any. void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual, MD->getLocation()) == DiagnosticsEngine::Ignored) return; if (MD->getDeclName().getNameKind() != DeclarationName::Identifier) return; CXXBasePaths Paths(/*FindAmbiguities=*/true, // true to look in all bases. /*bool RecordPaths=*/false, /*bool DetectVirtual=*/false); FindHiddenVirtualMethodData Data; Data.Method = MD; Data.S = this; // Keep the base methods that were overriden or introduced in the subclass // by 'using' in a set. A base method not in this set is hidden. for (DeclContext::lookup_result res = DC->lookup(MD->getDeclName()); res.first != res.second; ++res.first) { if (CXXMethodDecl *MD = dyn_cast(*res.first)) for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) Data.OverridenAndUsingBaseMethods.insert((*I)->getCanonicalDecl()); if (UsingShadowDecl *shad = dyn_cast(*res.first)) if (CXXMethodDecl *MD = dyn_cast(shad->getTargetDecl())) Data.OverridenAndUsingBaseMethods.insert(MD->getCanonicalDecl()); } if (DC->lookupInBases(&FindHiddenVirtualMethod, &Data, Paths) && !Data.OverloadedMethods.empty()) { Diag(MD->getLocation(), diag::warn_overloaded_virtual) << MD << (Data.OverloadedMethods.size() > 1); for (unsigned i = 0, e = Data.OverloadedMethods.size(); i != e; ++i) { CXXMethodDecl *overloadedMD = Data.OverloadedMethods[i]; Diag(overloadedMD->getLocation(), diag::note_hidden_overloaded_virtual_declared_here) << overloadedMD; } } } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList) { if (!TagDecl) return; AdjustDeclIfTemplate(TagDecl); ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef( // strict aliasing violation! reinterpret_cast(FieldCollector->getCurFields()), FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); CheckCompletedCXXClass( dyn_cast_or_null(TagDecl)); } /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared /// special functions, such as the default constructor, copy /// constructor, or destructor, to the given C++ class (C++ /// [special]p1). This routine can only be executed just before the /// definition of the class is complete. void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { if (!ClassDecl->hasUserDeclaredConstructor()) ++ASTContext::NumImplicitDefaultConstructors; if (!ClassDecl->hasUserDeclaredCopyConstructor()) ++ASTContext::NumImplicitCopyConstructors; if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveConstructor()) ++ASTContext::NumImplicitMoveConstructors; if (!ClassDecl->hasUserDeclaredCopyAssignment()) { ++ASTContext::NumImplicitCopyAssignmentOperators; // If we have a dynamic class, then the copy assignment operator may be // virtual, so we have to declare it immediately. This ensures that, e.g., // it shows up in the right place in the vtable and that we diagnose // problems with the implicit exception specification. if (ClassDecl->isDynamicClass()) DeclareImplicitCopyAssignment(ClassDecl); } if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveAssignment()) { ++ASTContext::NumImplicitMoveAssignmentOperators; // Likewise for the move assignment operator. if (ClassDecl->isDynamicClass()) DeclareImplicitMoveAssignment(ClassDecl); } if (!ClassDecl->hasUserDeclaredDestructor()) { ++ASTContext::NumImplicitDestructors; // If we have a dynamic class, then the destructor may be virtual, so we // have to declare the destructor immediately. This ensures that, e.g., it // shows up in the right place in the vtable and that we diagnose problems // with the implicit exception specification. if (ClassDecl->isDynamicClass()) DeclareImplicitDestructor(ClassDecl); } } void Sema::ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D) { if (!D) return; int NumParamList = D->getNumTemplateParameterLists(); for (int i = 0; i < NumParamList; i++) { TemplateParameterList* Params = D->getTemplateParameterList(i); for (TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); Param != ParamEnd; ++Param) { NamedDecl *Named = cast(*Param); if (Named->getDeclName()) { S->AddDecl(Named); IdResolver.AddDecl(Named); } } } } void Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { if (!D) return; TemplateParameterList *Params = 0; if (TemplateDecl *Template = dyn_cast(D)) Params = Template->getTemplateParameters(); else if (ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast(D)) Params = PartialSpec->getTemplateParameters(); else return; for (TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); Param != ParamEnd; ++Param) { NamedDecl *Named = cast(*Param); if (Named->getDeclName()) { S->AddDecl(Named); IdResolver.AddDecl(Named); } } } void Sema::ActOnStartDelayedMemberDeclarations(Scope *S, Decl *RecordD) { if (!RecordD) return; AdjustDeclIfTemplate(RecordD); CXXRecordDecl *Record = cast(RecordD); PushDeclContext(S, Record); } void Sema::ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *RecordD) { if (!RecordD) return; PopDeclContext(); } /// ActOnStartDelayedCXXMethodDeclaration - We have completed /// parsing a top-level (non-nested) C++ class, and we are now /// parsing those parts of the given Method declaration that could /// not be parsed earlier (C++ [class.mem]p2), such as default /// arguments. This action should enter the scope of the given /// Method declaration as if we had just parsed the qualified method /// name. However, it should not bring the parameters into scope; /// that will be performed by ActOnDelayedCXXMethodParameter. void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *MethodD) { } /// ActOnDelayedCXXMethodParameter - We've already started a delayed /// C++ method declaration. We're (re-)introducing the given /// function parameter into scope for use in parsing later parts of /// the method declaration. For example, we could see an /// ActOnParamDefaultArgument event for this parameter. void Sema::ActOnDelayedCXXMethodParameter(Scope *S, Decl *ParamD) { if (!ParamD) return; ParmVarDecl *Param = cast(ParamD); // If this parameter has an unparsed default argument, clear it out // to make way for the parsed default argument. if (Param->hasUnparsedDefaultArg()) Param->setDefaultArg(0); S->AddDecl(Param); if (Param->getDeclName()) IdResolver.AddDecl(Param); } /// ActOnFinishDelayedCXXMethodDeclaration - We have finished /// processing the delayed method declaration for Method. The method /// declaration is now considered finished. There may be a separate /// ActOnStartOfFunctionDef action later (not necessarily /// immediately!) for this method, if it was also defined inside the /// class body. void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *MethodD) { if (!MethodD) return; AdjustDeclIfTemplate(MethodD); FunctionDecl *Method = cast(MethodD); // Now that we have our default arguments, check the constructor // again. It could produce additional diagnostics or affect whether // the class has implicitly-declared destructors, among other // things. if (CXXConstructorDecl *Constructor = dyn_cast(Method)) CheckConstructor(Constructor); // Check the default arguments, which we may have added. if (!Method->isInvalidDecl()) CheckCXXDefaultArguments(Method); } /// CheckConstructorDeclarator - Called by ActOnDeclarator to check /// the well-formedness of the constructor declarator @p D with type @p /// R. If there are any errors in the declarator, this routine will /// emit diagnostics and set the invalid bit to true. In any case, the type /// will be updated to reflect a well-formed type for the constructor and /// returned. QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, StorageClass &SC) { bool isVirtual = D.getDeclSpec().isVirtualSpecified(); // C++ [class.ctor]p3: // A constructor shall not be virtual (10.3) or static (9.4). A // constructor can be invoked for a const, volatile or const // volatile object. A constructor shall not be declared const, // volatile, or const volatile (9.3.2). if (isVirtual) { if (!D.isInvalidType()) Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be) << "virtual" << SourceRange(D.getDeclSpec().getVirtualSpecLoc()) << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); } if (SC == SC_Static) { if (!D.isInvalidType()) Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be) << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); SC = SC_None; } DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); if (FTI.TypeQuals != 0) { if (FTI.TypeQuals & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "const" << SourceRange(D.getIdentifierLoc()); if (FTI.TypeQuals & Qualifiers::Volatile) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "volatile" << SourceRange(D.getIdentifierLoc()); if (FTI.TypeQuals & Qualifiers::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "restrict" << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); } // C++0x [class.ctor]p4: // A constructor shall not be declared with a ref-qualifier. if (FTI.hasRefQualifier()) { Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_constructor) << FTI.RefQualifierIsLValueRef << FixItHint::CreateRemoval(FTI.getRefQualifierLoc()); D.setInvalidType(); } // Rebuild the function type "R" without any type qualifiers (in // case any of the errors above fired) and with "void" as the // return type, since constructors don't have return types. const FunctionProtoType *Proto = R->getAs(); if (Proto->getResultType() == Context.VoidTy && !D.isInvalidType()) return R; FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); EPI.TypeQuals = 0; EPI.RefQualifier = RQ_None; return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(), Proto->getNumArgs(), EPI); } /// CheckConstructor - Checks a fully-formed constructor for /// well-formedness, issuing any diagnostics required. Returns true if /// the constructor declarator is invalid. void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { CXXRecordDecl *ClassDecl = dyn_cast(Constructor->getDeclContext()); if (!ClassDecl) return Constructor->setInvalidDecl(); // C++ [class.copy]p3: // A declaration of a constructor for a class X is ill-formed if // its first parameter is of type (optionally cv-qualified) X and // either there are no other parameters or else all other // parameters have default arguments. if (!Constructor->isInvalidDecl() && ((Constructor->getNumParams() == 1) || (Constructor->getNumParams() > 1 && Constructor->getParamDecl(1)->hasDefaultArg())) && Constructor->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { QualType ParamType = Constructor->getParamDecl(0)->getType(); QualType ClassTy = Context.getTagDeclType(ClassDecl); if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation(); const char *ConstRef = Constructor->getParamDecl(0)->getIdentifier() ? "const &" : " const &"; Diag(ParamLoc, diag::err_constructor_byvalue_arg) << FixItHint::CreateInsertion(ParamLoc, ConstRef); // FIXME: Rather that making the constructor invalid, we should endeavor // to fix the type. Constructor->setInvalidDecl(); } } } /// CheckDestructor - Checks a fully-formed destructor definition for /// well-formedness, issuing any diagnostics required. Returns true /// on error. bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) { CXXRecordDecl *RD = Destructor->getParent(); if (Destructor->isVirtual()) { SourceLocation Loc; if (!Destructor->isImplicit()) Loc = Destructor->getLocation(); else Loc = RD->getLocation(); // If we have a virtual destructor, look up the deallocation function FunctionDecl *OperatorDelete = 0; DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) return true; MarkFunctionReferenced(Loc, OperatorDelete); Destructor->setOperatorDelete(OperatorDelete); } return false; } static inline bool FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) { return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && FTI.ArgInfo[0].Param && cast(FTI.ArgInfo[0].Param)->getType()->isVoidType()); } /// CheckDestructorDeclarator - Called by ActOnDeclarator to check /// the well-formednes of the destructor declarator @p D with type @p /// R. If there are any errors in the declarator, this routine will /// emit diagnostics and set the declarator to invalid. Even if this happens, /// will be updated to reflect a well-formed type for the destructor and /// returned. QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, StorageClass& SC) { // C++ [class.dtor]p1: // [...] A typedef-name that names a class is a class-name // (7.1.3); however, a typedef-name that names a class shall not // be used as the identifier in the declarator for a destructor // declaration. QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName); if (const TypedefType *TT = DeclaratorType->getAs()) Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType << isa(TT->getDecl()); else if (const TemplateSpecializationType *TST = DeclaratorType->getAs()) if (TST->isTypeAlias()) Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType << 1; // C++ [class.dtor]p2: // A destructor is used to destroy objects of its class type. A // destructor takes no parameters, and no return type can be // specified for it (not even void). The address of a destructor // shall not be taken. A destructor shall not be static. A // destructor can be invoked for a const, volatile or const // volatile object. A destructor shall not be declared const, // volatile or const volatile (9.3.2). if (SC == SC_Static) { if (!D.isInvalidType()) Diag(D.getIdentifierLoc(), diag::err_destructor_cannot_be) << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) << SourceRange(D.getIdentifierLoc()) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); SC = SC_None; } if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Destructors don't have return types, but the parser will // happily parse something like: // // class X { // float ~X(); // }; // // The return type will be eliminated later. Diag(D.getIdentifierLoc(), diag::err_destructor_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); } DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); if (FTI.TypeQuals != 0 && !D.isInvalidType()) { if (FTI.TypeQuals & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "const" << SourceRange(D.getIdentifierLoc()); if (FTI.TypeQuals & Qualifiers::Volatile) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "volatile" << SourceRange(D.getIdentifierLoc()); if (FTI.TypeQuals & Qualifiers::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "restrict" << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); } // C++0x [class.dtor]p2: // A destructor shall not be declared with a ref-qualifier. if (FTI.hasRefQualifier()) { Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_destructor) << FTI.RefQualifierIsLValueRef << FixItHint::CreateRemoval(FTI.getRefQualifierLoc()); D.setInvalidType(); } // Make sure we don't have any parameters. if (FTI.NumArgs > 0 && !FTIHasSingleVoidArgument(FTI)) { Diag(D.getIdentifierLoc(), diag::err_destructor_with_params); // Delete the parameters. FTI.freeArgs(); D.setInvalidType(); } // Make sure the destructor isn't variadic. if (FTI.isVariadic) { Diag(D.getIdentifierLoc(), diag::err_destructor_variadic); D.setInvalidType(); } // Rebuild the function type "R" without any type qualifiers or // parameters (in case any of the errors above fired) and with // "void" as the return type, since destructors don't have return // types. if (!D.isInvalidType()) return R; const FunctionProtoType *Proto = R->getAs(); FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); EPI.Variadic = false; EPI.TypeQuals = 0; EPI.RefQualifier = RQ_None; return Context.getFunctionType(Context.VoidTy, 0, 0, EPI); } /// CheckConversionDeclarator - Called by ActOnDeclarator to check the /// well-formednes of the conversion function declarator @p D with /// type @p R. If there are any errors in the declarator, this routine /// will emit diagnostics and return true. Otherwise, it will return /// false. Either way, the type @p R will be updated to reflect a /// well-formed type for the conversion operator. void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, StorageClass& SC) { // C++ [class.conv.fct]p1: // Neither parameter types nor return type can be specified. The // type of a conversion function (8.3.5) is "function taking no // parameter returning conversion-type-id." if (SC == SC_Static) { if (!D.isInvalidType()) Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member) << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); SC = SC_None; } QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Conversion functions don't have return types, but the parser will // happily parse something like: // // class X { // float operator bool(); // }; // // The return type will be changed later anyway. Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); } const FunctionProtoType *Proto = R->getAs(); // Make sure we don't have any parameters. if (Proto->getNumArgs() > 0) { Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params); // Delete the parameters. D.getFunctionTypeInfo().freeArgs(); D.setInvalidType(); } else if (Proto->isVariadic()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); D.setInvalidType(); } // Diagnose "&operator bool()" and other such nonsense. This // is actually a gcc extension which we don't support. if (Proto->getResultType() != ConvType) { Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl) << Proto->getResultType(); D.setInvalidType(); ConvType = Proto->getResultType(); } // C++ [class.conv.fct]p4: // The conversion-type-id shall not represent a function type nor // an array type. if (ConvType->isArrayType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); ConvType = Context.getPointerType(ConvType); D.setInvalidType(); } else if (ConvType->isFunctionType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_function); ConvType = Context.getPointerType(ConvType); D.setInvalidType(); } // Rebuild the function type "R" without any parameters (in case any // of the errors above fired) and with the conversion type as the // return type. if (D.isInvalidType()) R = Context.getFunctionType(ConvType, 0, 0, Proto->getExtProtoInfo()); // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified()) Diag(D.getDeclSpec().getExplicitSpecLoc(), getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_explicit_conversion_functions : diag::ext_explicit_conversion_functions) << SourceRange(D.getDeclSpec().getExplicitSpecLoc()); } /// ActOnConversionDeclarator - Called by ActOnDeclarator to complete /// the declaration of the given C++ conversion function. This routine /// is responsible for recording the conversion function in the C++ /// class, if possible. Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { assert(Conversion && "Expected to receive a conversion function declaration"); CXXRecordDecl *ClassDecl = cast(Conversion->getDeclContext()); // Make sure we aren't redeclaring the conversion function. QualType ConvType = Context.getCanonicalType(Conversion->getConversionType()); // C++ [class.conv.fct]p1: // [...] A conversion function is never used to convert a // (possibly cv-qualified) object to the (possibly cv-qualified) // same object type (or a reference to it), to a (possibly // cv-qualified) base class of that type (or a reference to it), // or to (possibly cv-qualified) void. // FIXME: Suppress this warning if the conversion function ends up being a // virtual function that overrides a virtual function in a base class. QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); if (const ReferenceType *ConvTypeRef = ConvType->getAs()) ConvType = ConvTypeRef->getPointeeType(); if (Conversion->getTemplateSpecializationKind() != TSK_Undeclared && Conversion->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) /* Suppress diagnostics for instantiations. */; else if (ConvType->isRecordType()) { ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType(); if (ConvType == ClassType) Diag(Conversion->getLocation(), diag::warn_conv_to_self_not_used) << ClassType; else if (IsDerivedFrom(ClassType, ConvType)) Diag(Conversion->getLocation(), diag::warn_conv_to_base_not_used) << ClassType << ConvType; } else if (ConvType->isVoidType()) { Diag(Conversion->getLocation(), diag::warn_conv_to_void_not_used) << ClassType << ConvType; } if (FunctionTemplateDecl *ConversionTemplate = Conversion->getDescribedFunctionTemplate()) return ConversionTemplate; return Conversion; } //===----------------------------------------------------------------------===// // Namespace Handling //===----------------------------------------------------------------------===// /// ActOnStartNamespaceDef - This is called at the start of a namespace /// definition. Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, SourceLocation InlineLoc, SourceLocation NamespaceLoc, SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation LBrace, AttributeList *AttrList) { SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc; // For anonymous namespace, take the location of the left brace. SourceLocation Loc = II ? IdentLoc : LBrace; bool IsInline = InlineLoc.isValid(); bool IsInvalid = false; bool IsStd = false; bool AddToKnown = false; Scope *DeclRegionScope = NamespcScope->getParent(); NamespaceDecl *PrevNS = 0; if (II) { // C++ [namespace.def]p2: // The identifier in an original-namespace-definition shall not // have been previously defined in the declarative region in // which the original-namespace-definition appears. The // identifier in an original-namespace-definition is the name of // the namespace. Subsequently in that declarative region, it is // treated as an original-namespace-name. // // Since namespace names are unique in their scope, and we don't // look through using directives, just look for any ordinary names. const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member | Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag | Decl::IDNS_Namespace; NamedDecl *PrevDecl = 0; for (DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II); R.first != R.second; ++R.first) { if ((*R.first)->getIdentifierNamespace() & IDNS) { PrevDecl = *R.first; break; } } PrevNS = dyn_cast_or_null(PrevDecl); if (PrevNS) { // This is an extended namespace definition. if (IsInline != PrevNS->isInline()) { // inline-ness must match if (PrevNS->isInline()) { // The user probably just forgot the 'inline', so suggest that it // be added back. Diag(Loc, diag::warn_inline_namespace_reopened_noninline) << FixItHint::CreateInsertion(NamespaceLoc, "inline "); } else { Diag(Loc, diag::err_inline_namespace_mismatch) << IsInline; } Diag(PrevNS->getLocation(), diag::note_previous_definition); IsInline = PrevNS->isInline(); } } else if (PrevDecl) { // This is an invalid name redefinition. Diag(Loc, diag::err_redefinition_different_kind) << II; Diag(PrevDecl->getLocation(), diag::note_previous_definition); IsInvalid = true; // Continue on to push Namespc as current DeclContext and return it. } else if (II->isStr("std") && CurContext->getRedeclContext()->isTranslationUnit()) { // This is the first "real" definition of the namespace "std", so update // our cache of the "std" namespace to point at this definition. PrevNS = getStdNamespace(); IsStd = true; AddToKnown = !IsInline; } else { // We've seen this namespace for the first time. AddToKnown = !IsInline; } } else { // Anonymous namespaces. // Determine whether the parent already has an anonymous namespace. DeclContext *Parent = CurContext->getRedeclContext(); if (TranslationUnitDecl *TU = dyn_cast(Parent)) { PrevNS = TU->getAnonymousNamespace(); } else { NamespaceDecl *ND = cast(Parent); PrevNS = ND->getAnonymousNamespace(); } if (PrevNS && IsInline != PrevNS->isInline()) { // inline-ness must match Diag(Loc, diag::err_inline_namespace_mismatch) << IsInline; Diag(PrevNS->getLocation(), diag::note_previous_definition); // Recover by ignoring the new namespace's inline status. IsInline = PrevNS->isInline(); } } NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline, StartLoc, Loc, II, PrevNS); if (IsInvalid) Namespc->setInvalidDecl(); ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); // FIXME: Should we be merging attributes? if (const VisibilityAttr *Attr = Namespc->getAttr()) PushNamespaceVisibilityAttr(Attr, Loc); if (IsStd) StdNamespace = Namespc; if (AddToKnown) KnownNamespaces[Namespc] = false; if (II) { PushOnScopeChains(Namespc, DeclRegionScope); } else { // Link the anonymous namespace into its parent. DeclContext *Parent = CurContext->getRedeclContext(); if (TranslationUnitDecl *TU = dyn_cast(Parent)) { TU->setAnonymousNamespace(Namespc); } else { cast(Parent)->setAnonymousNamespace(Namespc); } CurContext->addDecl(Namespc); // C++ [namespace.unnamed]p1. An unnamed-namespace-definition // behaves as if it were replaced by // namespace unique { /* empty body */ } // using namespace unique; // namespace unique { namespace-body } // where all occurrences of 'unique' in a translation unit are // replaced by the same identifier and this identifier differs // from all other identifiers in the entire program. // We just create the namespace with an empty name and then add an // implicit using declaration, just like the standard suggests. // // CodeGen enforces the "universally unique" aspect by giving all // declarations semantically contained within an anonymous // namespace internal linkage. if (!PrevNS) { UsingDirectiveDecl* UD = UsingDirectiveDecl::Create(Context, CurContext, /* 'using' */ LBrace, /* 'namespace' */ SourceLocation(), /* qualifier */ NestedNameSpecifierLoc(), /* identifier */ SourceLocation(), Namespc, /* Ancestor */ CurContext); UD->setImplicit(); CurContext->addDecl(UD); } } // Although we could have an invalid decl (i.e. the namespace name is a // redefinition), push it as current DeclContext and try to continue parsing. // FIXME: We should be able to push Namespc here, so that the each DeclContext // for the namespace has the declarations that showed up in that particular // namespace definition. PushDeclContext(NamespcScope, Namespc); return Namespc; } /// getNamespaceDecl - Returns the namespace a decl represents. If the decl /// is a namespace alias, returns the namespace it points to. static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) { if (NamespaceAliasDecl *AD = dyn_cast_or_null(D)) return AD->getNamespace(); return dyn_cast_or_null(D); } /// ActOnFinishNamespaceDef - This callback is called after a namespace is /// exited. Decl is the DeclTy returned by ActOnStartNamespaceDef. void Sema::ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace) { NamespaceDecl *Namespc = dyn_cast_or_null(Dcl); assert(Namespc && "Invalid parameter, expected NamespaceDecl"); Namespc->setRBraceLoc(RBrace); PopDeclContext(); if (Namespc->hasAttr()) PopPragmaVisibility(true, RBrace); } CXXRecordDecl *Sema::getStdBadAlloc() const { return cast_or_null( StdBadAlloc.get(Context.getExternalSource())); } NamespaceDecl *Sema::getStdNamespace() const { return cast_or_null( StdNamespace.get(Context.getExternalSource())); } /// \brief Retrieve the special "std" namespace, which may require us to /// implicitly define the namespace. NamespaceDecl *Sema::getOrCreateStdNamespace() { if (!StdNamespace) { // The "std" namespace has not yet been defined, so build one implicitly. StdNamespace = NamespaceDecl::Create(Context, Context.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(), SourceLocation(), &PP.getIdentifierTable().get("std"), /*PrevDecl=*/0); getStdNamespace()->setImplicit(true); } return getStdNamespace(); } bool Sema::isStdInitializerList(QualType Ty, QualType *Element) { assert(getLangOpts().CPlusPlus && "Looking for std::initializer_list outside of C++."); // We're looking for implicit instantiations of // template class std::initializer_list. if (!StdNamespace) // If we haven't seen namespace std yet, this can't be it. return false; ClassTemplateDecl *Template = 0; const TemplateArgument *Arguments = 0; if (const RecordType *RT = Ty->getAs()) { ClassTemplateSpecializationDecl *Specialization = dyn_cast(RT->getDecl()); if (!Specialization) return false; Template = Specialization->getSpecializedTemplate(); Arguments = Specialization->getTemplateArgs().data(); } else if (const TemplateSpecializationType *TST = Ty->getAs()) { Template = dyn_cast_or_null( TST->getTemplateName().getAsTemplateDecl()); Arguments = TST->getArgs(); } if (!Template) return false; if (!StdInitializerList) { // Haven't recognized std::initializer_list yet, maybe this is it. CXXRecordDecl *TemplateClass = Template->getTemplatedDecl(); if (TemplateClass->getIdentifier() != &PP.getIdentifierTable().get("initializer_list") || !getStdNamespace()->InEnclosingNamespaceSetOf( TemplateClass->getDeclContext())) return false; // This is a template called std::initializer_list, but is it the right // template? TemplateParameterList *Params = Template->getTemplateParameters(); if (Params->getMinRequiredArguments() != 1) return false; if (!isa(Params->getParam(0))) return false; // It's the right template. StdInitializerList = Template; } if (Template != StdInitializerList) return false; // This is an instance of std::initializer_list. Find the argument type. if (Element) *Element = Arguments[0].getAsType(); return true; } static ClassTemplateDecl *LookupStdInitializerList(Sema &S, SourceLocation Loc){ NamespaceDecl *Std = S.getStdNamespace(); if (!Std) { S.Diag(Loc, diag::err_implied_std_initializer_list_not_found); return 0; } LookupResult Result(S, &S.PP.getIdentifierTable().get("initializer_list"), Loc, Sema::LookupOrdinaryName); if (!S.LookupQualifiedName(Result, Std)) { S.Diag(Loc, diag::err_implied_std_initializer_list_not_found); return 0; } ClassTemplateDecl *Template = Result.getAsSingle(); if (!Template) { Result.suppressDiagnostics(); // We found something weird. Complain about the first thing we found. NamedDecl *Found = *Result.begin(); S.Diag(Found->getLocation(), diag::err_malformed_std_initializer_list); return 0; } // We found some template called std::initializer_list. Now verify that it's // correct. TemplateParameterList *Params = Template->getTemplateParameters(); if (Params->getMinRequiredArguments() != 1 || !isa(Params->getParam(0))) { S.Diag(Template->getLocation(), diag::err_malformed_std_initializer_list); return 0; } return Template; } QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) { if (!StdInitializerList) { StdInitializerList = LookupStdInitializerList(*this, Loc); if (!StdInitializerList) return QualType(); } TemplateArgumentListInfo Args(Loc, Loc); Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element), Context.getTrivialTypeSourceInfo(Element, Loc))); return Context.getCanonicalType( CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args)); } bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) { // C++ [dcl.init.list]p2: // A constructor is an initializer-list constructor if its first parameter // is of type std::initializer_list or reference to possibly cv-qualified // std::initializer_list for some type E, and either there are no other // parameters or else all other parameters have default arguments. if (Ctor->getNumParams() < 1 || (Ctor->getNumParams() > 1 && !Ctor->getParamDecl(1)->hasDefaultArg())) return false; QualType ArgType = Ctor->getParamDecl(0)->getType(); if (const ReferenceType *RT = ArgType->getAs()) ArgType = RT->getPointeeType().getUnqualifiedType(); return isStdInitializerList(ArgType, 0); } /// \brief Determine whether a using statement is in a context where it will be /// apply in all contexts. static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) { switch (CurContext->getDeclKind()) { case Decl::TranslationUnit: return true; case Decl::LinkageSpec: return IsUsingDirectiveInToplevelContext(CurContext->getParent()); default: return false; } } namespace { // Callback to only accept typo corrections that are namespaces. class NamespaceValidatorCCC : public CorrectionCandidateCallback { public: virtual bool ValidateCandidate(const TypoCorrection &candidate) { if (NamedDecl *ND = candidate.getCorrectionDecl()) { return isa(ND) || isa(ND); } return false; } }; } static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident) { NamespaceValidatorCCC Validator; R.clear(); if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), Sc, &SS, Validator)) { std::string CorrectedStr(Corrected.getAsString(S.getLangOpts())); std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOpts())); if (DeclContext *DC = S.computeDeclContext(SS, false)) S.Diag(IdentLoc, diag::err_using_directive_member_suggest) << Ident << DC << CorrectedQuotedStr << SS.getRange() << FixItHint::CreateReplacement(IdentLoc, CorrectedStr); else S.Diag(IdentLoc, diag::err_using_directive_suggest) << Ident << CorrectedQuotedStr << FixItHint::CreateReplacement(IdentLoc, CorrectedStr); S.Diag(Corrected.getCorrectionDecl()->getLocation(), diag::note_namespace_defined_here) << CorrectedQuotedStr; R.addDecl(Corrected.getCorrectionDecl()); return true; } return false; } Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, SourceLocation NamespcLoc, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); assert(NamespcName && "Invalid NamespcName."); assert(IdentLoc.isValid() && "Invalid NamespceName location."); // This can only happen along a recovery path. while (S->getFlags() & Scope::TemplateParamScope) S = S->getParent(); assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); UsingDirectiveDecl *UDir = 0; NestedNameSpecifier *Qualifier = 0; if (SS.isSet()) Qualifier = static_cast(SS.getScopeRep()); // Lookup namespace name. LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName); LookupParsedName(R, S, &SS); if (R.isAmbiguous()) return 0; if (R.empty()) { R.clear(); // Allow "using namespace std;" or "using namespace ::std;" even if // "std" hasn't been defined yet, for GCC compatibility. if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) && NamespcName->isStr("std")) { Diag(IdentLoc, diag::ext_using_undefined_std); R.addDecl(getOrCreateStdNamespace()); R.resolveKind(); } // Otherwise, attempt typo correction. else TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName); } if (!R.empty()) { NamedDecl *Named = R.getFoundDecl(); assert((isa(Named) || isa(Named)) && "expected namespace decl"); // C++ [namespace.udir]p1: // A using-directive specifies that the names in the nominated // namespace can be used in the scope in which the // using-directive appears after the using-directive. 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". ] // Find enclosing context containing both using-directive and // nominated namespace. NamespaceDecl *NS = getNamespaceDecl(Named); DeclContext *CommonAncestor = cast(NS); while (CommonAncestor && !CommonAncestor->Encloses(CurContext)) CommonAncestor = CommonAncestor->getParent(); UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc, NamespcLoc, SS.getWithLocInContext(Context), IdentLoc, Named, CommonAncestor); if (IsUsingDirectiveInToplevelContext(CurContext) && !SourceMgr.isFromMainFile(SourceMgr.getExpansionLoc(IdentLoc))) { Diag(IdentLoc, diag::warn_using_directive_in_header); } PushUsingDirective(S, UDir); } else { Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange(); } // FIXME: We ignore attributes for now. return UDir; } void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { // If the scope has an associated entity and the using directive is at // namespace or translation unit scope, add the UsingDirectiveDecl into // its lookup structure so qualified name lookup can find it. DeclContext *Ctx = static_cast(S->getEntity()); if (Ctx && !Ctx->isFunctionOrMethod()) Ctx->addDecl(UDir); else // Otherwise, it is at block sope. The using-directives will affect lookup // only to the end of the scope. S->PushUsingDirective(UDir); } Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, SourceLocation TypenameLoc) { assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); switch (Name.getKind()) { case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_ConversionFunctionId: break; case UnqualifiedId::IK_ConstructorName: case UnqualifiedId::IK_ConstructorTemplateId: // C++11 inheriting constructors. Diag(Name.getLocStart(), getLangOpts().CPlusPlus0x ? // FIXME: Produce warn_cxx98_compat_using_decl_constructor // instead once inheriting constructors work. diag::err_using_decl_constructor_unsupported : diag::err_using_decl_constructor) << SS.getRange(); if (getLangOpts().CPlusPlus0x) break; return 0; case UnqualifiedId::IK_DestructorName: Diag(Name.getLocStart(), diag::err_using_decl_destructor) << SS.getRange(); return 0; case UnqualifiedId::IK_TemplateId: Diag(Name.getLocStart(), diag::err_using_decl_template_id) << SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc); return 0; } DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); DeclarationName TargetName = TargetNameInfo.getName(); if (!TargetName) return 0; // Warn about using declarations. // TODO: store that the declaration was written without 'using' and // talk about access decls instead of using decls in the // diagnostics. if (!HasUsingKeyword) { UsingLoc = Name.getLocStart(); Diag(UsingLoc, diag::warn_access_decl_deprecated) << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using "); } if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) || DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC_UsingDeclaration)) return 0; NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, TargetNameInfo, AttrList, /* IsInstantiation */ false, IsTypeName, TypenameLoc); if (UD) PushOnScopeChains(UD, S, /*AddToContext*/ false); return UD; } /// \brief Determine whether a using declaration considers the given /// declarations as "equivalent", e.g., if they are redeclarations of /// the same entity or are both typedefs of the same type. static bool IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2, bool &SuppressRedeclaration) { if (D1->getCanonicalDecl() == D2->getCanonicalDecl()) { SuppressRedeclaration = false; return true; } if (TypedefNameDecl *TD1 = dyn_cast(D1)) if (TypedefNameDecl *TD2 = dyn_cast(D2)) { SuppressRedeclaration = true; return Context.hasSameType(TD1->getUnderlyingType(), TD2->getUnderlyingType()); } return false; } /// Determines whether to create a using shadow decl for a particular /// decl, given the set of decls existing prior to this using lookup. bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, const LookupResult &Previous) { // Diagnose finding a decl which is not from a base class of the // current class. We do this now because there are cases where this // function will silently decide not to build a shadow decl, which // will pre-empt further diagnostics. // // We don't need to do this in C++0x because we do the check once on // the qualifier. // // FIXME: diagnose the following if we care enough: // struct A { int foo; }; // struct B : A { using A::foo; }; // template struct C : A {}; // template struct D : C { using B::foo; } // <--- // This is invalid (during instantiation) in C++03 because B::foo // resolves to the using decl in B, which is not a base class of D. // We can't diagnose it immediately because C is an unknown // specialization. The UsingShadowDecl in D then points directly // to A::foo, which will look well-formed when we instantiate. // The right solution is to not collapse the shadow-decl chain. if (!getLangOpts().CPlusPlus0x && CurContext->isRecord()) { DeclContext *OrigDC = Orig->getDeclContext(); // Handle enums and anonymous structs. if (isa(OrigDC)) OrigDC = OrigDC->getParent(); CXXRecordDecl *OrigRec = cast(OrigDC); while (OrigRec->isAnonymousStructOrUnion()) OrigRec = cast(OrigRec->getDeclContext()); if (cast(CurContext)->isProvablyNotDerivedFrom(OrigRec)) { if (OrigDC == CurContext) { Diag(Using->getLocation(), diag::err_using_decl_nested_name_specifier_is_current_class) << Using->getQualifierLoc().getSourceRange(); Diag(Orig->getLocation(), diag::note_using_decl_target); return true; } Diag(Using->getQualifierLoc().getBeginLoc(), diag::err_using_decl_nested_name_specifier_is_not_base_class) << Using->getQualifier() << cast(CurContext) << Using->getQualifierLoc().getSourceRange(); Diag(Orig->getLocation(), diag::note_using_decl_target); return true; } } if (Previous.empty()) return false; NamedDecl *Target = Orig; if (isa(Target)) Target = cast(Target)->getTargetDecl(); // If the target happens to be one of the previous declarations, we // don't have a conflict. // // FIXME: but we might be increasing its access, in which case we // should redeclare it. NamedDecl *NonTag = 0, *Tag = 0; for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); I != E; ++I) { NamedDecl *D = (*I)->getUnderlyingDecl(); bool Result; if (IsEquivalentForUsingDecl(Context, D, Target, Result)) return Result; (isa(D) ? Tag : NonTag) = D; } if (Target->isFunctionOrFunctionTemplate()) { FunctionDecl *FD; if (isa(Target)) FD = cast(Target)->getTemplatedDecl(); else FD = cast(Target); NamedDecl *OldDecl = 0; switch (CheckOverload(0, FD, Previous, OldDecl, /*IsForUsingDecl*/ true)) { case Ovl_Overload: return false; case Ovl_NonFunction: Diag(Using->getLocation(), diag::err_using_decl_conflict); break; // We found a decl with the exact signature. case Ovl_Match: // If we're in a record, we want to hide the target, so we // return true (without a diagnostic) to tell the caller not to // build a shadow decl. if (CurContext->isRecord()) return true; // If we're not in a record, this is an error. Diag(Using->getLocation(), diag::err_using_decl_conflict); break; } Diag(Target->getLocation(), diag::note_using_decl_target); Diag(OldDecl->getLocation(), diag::note_using_decl_conflict); return true; } // Target is not a function. if (isa(Target)) { // No conflict between a tag and a non-tag. if (!Tag) return false; Diag(Using->getLocation(), diag::err_using_decl_conflict); Diag(Target->getLocation(), diag::note_using_decl_target); Diag(Tag->getLocation(), diag::note_using_decl_conflict); return true; } // No conflict between a tag and a non-tag. if (!NonTag) return false; Diag(Using->getLocation(), diag::err_using_decl_conflict); Diag(Target->getLocation(), diag::note_using_decl_target); Diag(NonTag->getLocation(), diag::note_using_decl_conflict); return true; } /// Builds a shadow declaration corresponding to a 'using' declaration. UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, UsingDecl *UD, NamedDecl *Orig) { // If we resolved to another shadow declaration, just coalesce them. NamedDecl *Target = Orig; if (isa(Target)) { Target = cast(Target)->getTargetDecl(); assert(!isa(Target) && "nested shadow declaration"); } UsingShadowDecl *Shadow = UsingShadowDecl::Create(Context, CurContext, UD->getLocation(), UD, Target); UD->addShadowDecl(Shadow); Shadow->setAccess(UD->getAccess()); if (Orig->isInvalidDecl() || UD->isInvalidDecl()) Shadow->setInvalidDecl(); if (S) PushOnScopeChains(Shadow, S); else CurContext->addDecl(Shadow); return Shadow; } /// Hides a using shadow declaration. This is required by the current /// using-decl implementation when a resolvable using declaration in a /// class is followed by a declaration which would hide or override /// one or more of the using decl's targets; for example: /// /// struct Base { void foo(int); }; /// struct Derived : Base { /// using Base::foo; /// void foo(int); /// }; /// /// The governing language is C++03 [namespace.udecl]p12: /// /// When a using-declaration brings names from a base class into a /// derived class scope, member functions in the derived class /// override and/or hide member functions with the same name and /// parameter types in a base class (rather than conflicting). /// /// There are two ways to implement this: /// (1) optimistically create shadow decls when they're not hidden /// by existing declarations, or /// (2) don't create any shadow decls (or at least don't make them /// visible) until we've fully parsed/instantiated the class. /// The problem with (1) is that we might have to retroactively remove /// a shadow decl, which requires several O(n) operations because the /// decl structures are (very reasonably) not designed for removal. /// (2) avoids this but is very fiddly and phase-dependent. void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { if (Shadow->getDeclName().getNameKind() == DeclarationName::CXXConversionFunctionName) cast(Shadow->getDeclContext())->removeConversion(Shadow); // Remove it from the DeclContext... Shadow->getDeclContext()->removeDecl(Shadow); // ...and the scope, if applicable... if (S) { S->RemoveDecl(Shadow); IdResolver.RemoveDecl(Shadow); } // ...and the using decl. Shadow->getUsingDecl()->removeShadowDecl(Shadow); // TODO: complain somehow if Shadow was used. It shouldn't // be possible for this to happen, because...? } /// Builds a using declaration. /// /// \param IsInstantiation - Whether this call arises from an /// instantiation of an unresolved using declaration. We treat /// the lookup differently for these declarations. NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, AttributeList *AttrList, bool IsInstantiation, bool IsTypeName, SourceLocation TypenameLoc) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); SourceLocation IdentLoc = NameInfo.getLoc(); assert(IdentLoc.isValid() && "Invalid TargetName location."); // FIXME: We ignore attributes for now. if (SS.isEmpty()) { Diag(IdentLoc, diag::err_using_requires_qualname); return 0; } // Do the redeclaration lookup in the current scope. LookupResult Previous(*this, NameInfo, LookupUsingDeclName, ForRedeclaration); Previous.setHideTags(false); if (S) { LookupName(Previous, S); // It is really dumb that we have to do this. LookupResult::Filter F = Previous.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); if (!isDeclInScope(D, CurContext, S)) F.erase(); } F.done(); } else { assert(IsInstantiation && "no scope in non-instantiation"); assert(CurContext->isRecord() && "scope not record in instantiation"); LookupQualifiedName(Previous, CurContext); } // Check for invalid redeclarations. if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous)) return 0; // Check for bad qualifiers. if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc)) return 0; DeclContext *LookupContext = computeDeclContext(SS); NamedDecl *D; NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); if (!LookupContext) { if (IsTypeName) { // FIXME: not all declaration name kinds are legal here D = UnresolvedUsingTypenameDecl::Create(Context, CurContext, UsingLoc, TypenameLoc, QualifierLoc, IdentLoc, NameInfo.getName()); } else { D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc, QualifierLoc, NameInfo); } } else { D = UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc, NameInfo, IsTypeName); } D->setAccess(AS); CurContext->addDecl(D); if (!LookupContext) return D; UsingDecl *UD = cast(D); if (RequireCompleteDeclContext(SS, LookupContext)) { UD->setInvalidDecl(); return UD; } // The normal rules do not apply to inheriting constructor declarations. if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) { if (CheckInheritingConstructorUsingDecl(UD)) UD->setInvalidDecl(); return UD; } // Otherwise, look up the target name. LookupResult R(*this, NameInfo, LookupOrdinaryName); // Unlike most lookups, we don't always want to hide tag // declarations: tag names are visible through the using declaration // even if hidden by ordinary names, *except* in a dependent context // where it's important for the sanity of two-phase lookup. if (!IsInstantiation) R.setHideTags(false); // For the purposes of this lookup, we have a base object type // equal to that of the current context. if (CurContext->isRecord()) { R.setBaseObjectType( Context.getTypeDeclType(cast(CurContext))); } LookupQualifiedName(R, LookupContext); if (R.empty()) { Diag(IdentLoc, diag::err_no_member) << NameInfo.getName() << LookupContext << SS.getRange(); UD->setInvalidDecl(); return UD; } if (R.isAmbiguous()) { UD->setInvalidDecl(); return UD; } if (IsTypeName) { // If we asked for a typename and got a non-type decl, error out. if (!R.getAsSingle()) { Diag(IdentLoc, diag::err_using_typename_non_type); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) Diag((*I)->getUnderlyingDecl()->getLocation(), diag::note_using_decl_target); UD->setInvalidDecl(); return UD; } } else { // If we asked for a non-typename and we got a type, error out, // but only if this is an instantiation of an unresolved using // decl. Otherwise just silently find the type name. if (IsInstantiation && R.getAsSingle()) { Diag(IdentLoc, diag::err_using_dependent_value_is_type); Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target); UD->setInvalidDecl(); return UD; } } // C++0x N2914 [namespace.udecl]p6: // A using-declaration shall not name a namespace. if (R.getAsSingle()) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace) << SS.getRange(); UD->setInvalidDecl(); return UD; } for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (!CheckUsingShadowDecl(UD, *I, Previous)) BuildUsingShadowDecl(S, UD, *I); } return UD; } /// Additional checks for a using declaration referring to a constructor name. bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) { assert(!UD->isTypeName() && "expecting a constructor name"); const Type *SourceType = UD->getQualifier()->getAsType(); assert(SourceType && "Using decl naming constructor doesn't have type in scope spec."); CXXRecordDecl *TargetClass = cast(CurContext); // Check whether the named type is a direct base class. CanQualType CanonicalSourceType = SourceType->getCanonicalTypeUnqualified(); CXXRecordDecl::base_class_iterator BaseIt, BaseE; for (BaseIt = TargetClass->bases_begin(), BaseE = TargetClass->bases_end(); BaseIt != BaseE; ++BaseIt) { CanQualType BaseType = BaseIt->getType()->getCanonicalTypeUnqualified(); if (CanonicalSourceType == BaseType) break; if (BaseIt->getType()->isDependentType()) break; } if (BaseIt == BaseE) { // Did not find SourceType in the bases. Diag(UD->getUsingLocation(), diag::err_using_decl_constructor_not_in_direct_base) << UD->getNameInfo().getSourceRange() << QualType(SourceType, 0) << TargetClass; return true; } if (!CurContext->isDependentContext()) BaseIt->setInheritConstructors(); return false; } /// Checks that the given using declaration is not an invalid /// redeclaration. Note that this is checking only for the using decl /// itself, not for any ill-formedness among the UsingShadowDecls. bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, bool isTypeName, const CXXScopeSpec &SS, SourceLocation NameLoc, const LookupResult &Prev) { // C++03 [namespace.udecl]p8: // C++0x [namespace.udecl]p10: // A using-declaration is a declaration and can therefore be used // repeatedly where (and only where) multiple declarations are // allowed. // // That's in non-member contexts. if (!CurContext->getRedeclContext()->isRecord()) return false; NestedNameSpecifier *Qual = static_cast(SS.getScopeRep()); for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { NamedDecl *D = *I; bool DTypename; NestedNameSpecifier *DQual; if (UsingDecl *UD = dyn_cast(D)) { DTypename = UD->isTypeName(); DQual = UD->getQualifier(); } else if (UnresolvedUsingValueDecl *UD = dyn_cast(D)) { DTypename = false; DQual = UD->getQualifier(); } else if (UnresolvedUsingTypenameDecl *UD = dyn_cast(D)) { DTypename = true; DQual = UD->getQualifier(); } else continue; // using decls differ if one says 'typename' and the other doesn't. // FIXME: non-dependent using decls? if (isTypeName != DTypename) continue; // using decls differ if they name different scopes (but note that // template instantiation can cause this check to trigger when it // didn't before instantiation). if (Context.getCanonicalNestedNameSpecifier(Qual) != Context.getCanonicalNestedNameSpecifier(DQual)) continue; Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange(); Diag(D->getLocation(), diag::note_using_decl) << 1; return true; } return false; } /// Checks that the given nested-name qualifier used in a using decl /// in the current context is appropriately related to the current /// scope. If an error is found, diagnoses it and returns true. bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation NameLoc) { DeclContext *NamedContext = computeDeclContext(SS); if (!CurContext->isRecord()) { // C++03 [namespace.udecl]p3: // C++0x [namespace.udecl]p8: // A using-declaration for a class member shall be a member-declaration. // If we weren't able to compute a valid scope, it must be a // dependent class scope. if (!NamedContext || NamedContext->isRecord()) { Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member) << SS.getRange(); return true; } // Otherwise, everything is known to be fine. return false; } // The current scope is a record. // If the named context is dependent, we can't decide much. if (!NamedContext) { // FIXME: in C++0x, we can diagnose if we can prove that the // nested-name-specifier does not refer to a base class, which is // still possible in some cases. // Otherwise we have to conservatively report that things might be // okay. return false; } if (!NamedContext->isRecord()) { // Ideally this would point at the last name in the specifier, // but we don't have that level of source info. Diag(SS.getRange().getBegin(), diag::err_using_decl_nested_name_specifier_is_not_class) << (NestedNameSpecifier*) SS.getScopeRep() << SS.getRange(); return true; } if (!NamedContext->isDependentContext() && RequireCompleteDeclContext(const_cast(SS), NamedContext)) return true; if (getLangOpts().CPlusPlus0x) { // C++0x [namespace.udecl]p3: // In a using-declaration used as a member-declaration, the // nested-name-specifier shall name a base class of the class // being defined. if (cast(CurContext)->isProvablyNotDerivedFrom( cast(NamedContext))) { if (CurContext == NamedContext) { Diag(NameLoc, diag::err_using_decl_nested_name_specifier_is_current_class) << SS.getRange(); return true; } Diag(SS.getRange().getBegin(), diag::err_using_decl_nested_name_specifier_is_not_base_class) << (NestedNameSpecifier*) SS.getScopeRep() << cast(CurContext) << SS.getRange(); return true; } return false; } // C++03 [namespace.udecl]p4: // A using-declaration used as a member-declaration shall refer // to a member of a base class of the class being defined [etc.]. // Salient point: SS doesn't have to name a base class as long as // lookup only finds members from base classes. Therefore we can // diagnose here only if we can prove that that can't happen, // i.e. if the class hierarchies provably don't intersect. // TODO: it would be nice if "definitely valid" results were cached // in the UsingDecl and UsingShadowDecl so that these checks didn't // need to be repeated. struct UserData { llvm::SmallPtrSet Bases; static bool collect(const CXXRecordDecl *Base, void *OpaqueData) { UserData *Data = reinterpret_cast(OpaqueData); Data->Bases.insert(Base); return true; } bool hasDependentBases(const CXXRecordDecl *Class) { return !Class->forallBases(collect, this); } /// Returns true if the base is dependent or is one of the /// accumulated base classes. static bool doesNotContain(const CXXRecordDecl *Base, void *OpaqueData) { UserData *Data = reinterpret_cast(OpaqueData); return !Data->Bases.count(Base); } bool mightShareBases(const CXXRecordDecl *Class) { return Bases.count(Class) || !Class->forallBases(doesNotContain, this); } }; UserData Data; // Returns false if we find a dependent base. if (Data.hasDependentBases(cast(CurContext))) return false; // Returns false if the class has a dependent base or if it or one // of its bases is present in the base set of the current context. if (Data.mightShareBases(cast(NamedContext))) return false; Diag(SS.getRange().getBegin(), diag::err_using_decl_nested_name_specifier_is_not_base_class) << (NestedNameSpecifier*) SS.getScopeRep() << cast(CurContext) << SS.getRange(); return true; } Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, MultiTemplateParamsArg TemplateParamLists, SourceLocation UsingLoc, UnqualifiedId &Name, TypeResult Type) { // Skip up to the relevant declaration scope. while (S->getFlags() & Scope::TemplateParamScope) S = S->getParent(); assert((S->getFlags() & Scope::DeclScope) && "got alias-declaration outside of declaration scope"); if (Type.isInvalid()) return 0; bool Invalid = false; DeclarationNameInfo NameInfo = GetNameFromUnqualifiedId(Name); TypeSourceInfo *TInfo = 0; GetTypeFromParser(Type.get(), &TInfo); if (DiagnoseClassNameShadow(CurContext, NameInfo)) return 0; if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo, UPPC_DeclarationType)) { Invalid = true; TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, TInfo->getTypeLoc().getBeginLoc()); } LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); LookupName(Previous, S); // Warn about shadowing the name of a template parameter. if (Previous.isSingleResult() && Previous.getFoundDecl()->isTemplateParameter()) { DiagnoseTemplateParameterShadow(Name.StartLocation,Previous.getFoundDecl()); Previous.clear(); } assert(Name.Kind == UnqualifiedId::IK_Identifier && "name in alias declaration must be an identifier"); TypeAliasDecl *NewTD = TypeAliasDecl::Create(Context, CurContext, UsingLoc, Name.StartLocation, Name.Identifier, TInfo); NewTD->setAccess(AS); if (Invalid) NewTD->setInvalidDecl(); CheckTypedefForVariablyModifiedType(S, NewTD); Invalid |= NewTD->isInvalidDecl(); bool Redeclaration = false; NamedDecl *NewND; if (TemplateParamLists.size()) { TypeAliasTemplateDecl *OldDecl = 0; TemplateParameterList *OldTemplateParams = 0; if (TemplateParamLists.size() != 1) { Diag(UsingLoc, diag::err_alias_template_extra_headers) << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(), TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc()); } TemplateParameterList *TemplateParams = TemplateParamLists.get()[0]; // Only consider previous declarations in the same scope. FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false, /*ExplicitInstantiationOrSpecialization*/false); if (!Previous.empty()) { Redeclaration = true; OldDecl = Previous.getAsSingle(); if (!OldDecl && !Invalid) { Diag(UsingLoc, diag::err_redefinition_different_kind) << Name.Identifier; NamedDecl *OldD = Previous.getRepresentativeDecl(); if (OldD->getLocation().isValid()) Diag(OldD->getLocation(), diag::note_previous_definition); Invalid = true; } if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) { if (TemplateParameterListsAreEqual(TemplateParams, OldDecl->getTemplateParameters(), /*Complain=*/true, TPL_TemplateMatch)) OldTemplateParams = OldDecl->getTemplateParameters(); else Invalid = true; TypeAliasDecl *OldTD = OldDecl->getTemplatedDecl(); if (!Invalid && !Context.hasSameType(OldTD->getUnderlyingType(), NewTD->getUnderlyingType())) { // FIXME: The C++0x standard does not clearly say this is ill-formed, // but we can't reasonably accept it. Diag(NewTD->getLocation(), diag::err_redefinition_different_typedef) << 2 << NewTD->getUnderlyingType() << OldTD->getUnderlyingType(); if (OldTD->getLocation().isValid()) Diag(OldTD->getLocation(), diag::note_previous_definition); Invalid = true; } } } // Merge any previous default template arguments into our parameters, // and check the parameter list. if (CheckTemplateParameterList(TemplateParams, OldTemplateParams, TPC_TypeAliasTemplate)) return 0; TypeAliasTemplateDecl *NewDecl = TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc, Name.Identifier, TemplateParams, NewTD); NewDecl->setAccess(AS); if (Invalid) NewDecl->setInvalidDecl(); else if (OldDecl) NewDecl->setPreviousDeclaration(OldDecl); NewND = NewDecl; } else { ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration); NewND = NewTD; } if (!Redeclaration) PushOnScopeChains(NewND, S); return NewND; } Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident) { // Lookup the namespace name. LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName); LookupParsedName(R, S, &SS); // Check if we have a previous declaration with the same name. NamedDecl *PrevDecl = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName, ForRedeclaration); if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S)) PrevDecl = 0; if (PrevDecl) { if (NamespaceAliasDecl *AD = dyn_cast(PrevDecl)) { // We already have an alias with the same name that points to the same // namespace, so don't create a new one. // FIXME: At some point, we'll want to create the (redundant) // declaration to maintain better source information. if (!R.isAmbiguous() && !R.empty() && AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl()))) return 0; } unsigned DiagID = isa(PrevDecl) ? diag::err_redefinition : diag::err_redefinition_different_kind; Diag(AliasLoc, DiagID) << Alias; Diag(PrevDecl->getLocation(), diag::note_previous_definition); return 0; } if (R.isAmbiguous()) return 0; if (R.empty()) { if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) { Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange(); return 0; } } NamespaceAliasDecl *AliasDecl = NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc, Alias, SS.getWithLocInContext(Context), IdentLoc, R.getFoundDecl()); PushOnScopeChains(AliasDecl, S); return AliasDecl; } namespace { /// \brief Scoped object used to handle the state changes required in Sema /// to implicitly define the body of a C++ member function; class ImplicitlyDefinedFunctionScope { Sema &S; Sema::ContextRAII SavedContext; public: ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method) : S(S), SavedContext(S, Method) { S.PushFunctionScope(); S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); } ~ImplicitlyDefinedFunctionScope() { S.PopExpressionEvaluationContext(); S.PopFunctionScopeInfo(); } }; } Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; // Direct base-class constructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), BEnd = ClassDecl->bases_end(); B != BEnd; ++B) { if (B->isVirtual()) // Handled below. continue; if (const RecordType *BaseType = B->getType()->getAs()) { CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } // Virtual base-class constructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), BEnd = ClassDecl->vbases_end(); B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs()) { CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } // Field constructors. for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { if (F->hasInClassInitializer()) { if (Expr *E = F->getInClassInitializer()) ExceptSpec.CalledExpr(E); else if (!F->isInvalidDecl()) ExceptSpec.SetDelayed(); } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs()) { CXXRecordDecl *FieldRecDecl = cast(RecordTy->getDecl()); CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. // In particular, the problem is that this function never gets called. It // might just be ill-formed because this function attempts to refer to // a deleted function here. if (Constructor) ExceptSpec.CalledDecl(F->getLocation(), Constructor); } } return ExceptSpec; } CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXRecordDecl *ClassDecl) { // C++ [class.ctor]p5: // A default constructor for a class X is a constructor of class X // that can be called without an argument. If there is no // user-declared constructor for class X, a default constructor is // implicitly declared. An implicitly-declared default constructor // is an inline public member of its class. assert(!ClassDecl->hasUserDeclaredConstructor() && "Should not build implicit default constructor!"); ImplicitExceptionSpecification Spec = ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); // Create the actual constructor declaration. CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, /*isConstexpr=*/ClassDecl->defaultedDefaultConstructorIsConstexpr() && getLangOpts().CPlusPlus0x); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); DefaultCon->setImplicit(); DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); // Note that we have declared this constructor. ++ASTContext::NumImplicitDefaultConstructorsDeclared; if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(DefaultCon, S, false); ClassDecl->addDecl(DefaultCon); if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor)) DefaultCon->setDeletedAsWritten(); return DefaultCon; } void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor) { assert((Constructor->isDefaulted() && Constructor->isDefaultConstructor() && !Constructor->doesThisDeclarationHaveABody() && !Constructor->isDeleted()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); ImplicitlyDefinedFunctionScope Scope(*this, Constructor); DiagnosticErrorTrap Trap(Diags); if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); return; } SourceLocation Loc = Constructor->getLocation(); Constructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc)); Constructor->setUsed(); MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); } } /// Get any existing defaulted default constructor for the given class. Do not /// implicitly define one if it does not exist. static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self, CXXRecordDecl *D) { ASTContext &Context = Self.Context; QualType ClassType = Context.getTypeDeclType(D); DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType.getUnqualifiedType())); DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); Con != ConEnd; ++Con) { // A function template cannot be defaulted. if (isa(*Con)) continue; CXXConstructorDecl *Constructor = cast(*Con); if (Constructor->isDefaultConstructor()) return Constructor->isDefaulted() ? Constructor : 0; } return 0; } void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { if (!D) return; AdjustDeclIfTemplate(D); CXXRecordDecl *ClassDecl = cast(D); CXXConstructorDecl *CtorDecl = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl); if (!CtorDecl) return; // Compute the exception specification for the default constructor. const FunctionProtoType *CtorTy = CtorDecl->getType()->castAs(); if (CtorTy->getExceptionSpecType() == EST_Delayed) { // FIXME: Don't do this unless the exception spec is needed. ImplicitExceptionSpecification Spec = ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); assert(EPI.ExceptionSpecType != EST_Delayed); CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); } // If the default constructor is explicitly defaulted, checking the exception // specification is deferred until now. if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() && !ClassDecl->isDependentType()) CheckExplicitlyDefaultedDefaultConstructor(CtorDecl); } void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // We start with an initial pass over the base classes to collect those that // inherit constructors from. If there are none, we can forgo all further // processing. typedef SmallVector BasesVector; BasesVector BasesToInheritFrom; for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), BaseE = ClassDecl->bases_end(); BaseIt != BaseE; ++BaseIt) { if (BaseIt->getInheritConstructors()) { QualType Base = BaseIt->getType(); if (Base->isDependentType()) { // If we inherit constructors from anything that is dependent, just // abort processing altogether. We'll get another chance for the // instantiations. return; } BasesToInheritFrom.push_back(Base->castAs()); } } if (BasesToInheritFrom.empty()) return; // Now collect the constructors that we already have in the current class. // Those take precedence over inherited constructors. // C++0x [class.inhctor]p3: [...] a constructor is implicitly declared [...] // unless there is a user-declared constructor with the same signature in // the class where the using-declaration appears. llvm::SmallSet ExistingConstructors; for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(), CtorE = ClassDecl->ctor_end(); CtorIt != CtorE; ++CtorIt) { ExistingConstructors.insert( Context.getCanonicalType(CtorIt->getType()).getTypePtr()); } DeclarationName CreatedCtorName = Context.DeclarationNames.getCXXConstructorName( ClassDecl->getTypeForDecl()->getCanonicalTypeUnqualified()); // Now comes the true work. // First, we keep a map from constructor types to the base that introduced // them. Needed for finding conflicting constructors. We also keep the // actually inserted declarations in there, for pretty diagnostics. typedef std::pair ConstructorInfo; typedef llvm::DenseMap ConstructorToSourceMap; ConstructorToSourceMap InheritedConstructors; for (BasesVector::iterator BaseIt = BasesToInheritFrom.begin(), BaseE = BasesToInheritFrom.end(); BaseIt != BaseE; ++BaseIt) { const RecordType *Base = *BaseIt; CanQualType CanonicalBase = Base->getCanonicalTypeUnqualified(); CXXRecordDecl *BaseDecl = cast(Base->getDecl()); for (CXXRecordDecl::ctor_iterator CtorIt = BaseDecl->ctor_begin(), CtorE = BaseDecl->ctor_end(); CtorIt != CtorE; ++CtorIt) { // Find the using declaration for inheriting this base's constructors. // FIXME: Don't perform name lookup just to obtain a source location! DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(CanonicalBase); LookupResult Result(*this, Name, SourceLocation(), LookupUsingDeclName); LookupQualifiedName(Result, CurContext); UsingDecl *UD = Result.getAsSingle(); SourceLocation UsingLoc = UD ? UD->getLocation() : ClassDecl->getLocation(); // C++0x [class.inhctor]p1: The candidate set of inherited constructors // from the class X named in the using-declaration consists of actual // constructors and notional constructors that result from the // transformation of defaulted parameters as follows: // - all non-template default constructors of X, and // - for each non-template constructor of X that has at least one // parameter with a default argument, the set of constructors that // results from omitting any ellipsis parameter specification and // successively omitting parameters with a default argument from the // end of the parameter-type-list. CXXConstructorDecl *BaseCtor = *CtorIt; bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor(); const FunctionProtoType *BaseCtorType = BaseCtor->getType()->getAs(); for (unsigned params = BaseCtor->getMinRequiredArguments(), maxParams = BaseCtor->getNumParams(); params <= maxParams; ++params) { // Skip default constructors. They're never inherited. if (params == 0) continue; // Skip copy and move constructors for the same reason. if (CanBeCopyOrMove && params == 1) continue; // Build up a function type for this particular constructor. // FIXME: The working paper does not consider that the exception spec // for the inheriting constructor might be larger than that of the // source. This code doesn't yet, either. When it does, this code will // need to be delayed until after exception specifications and in-class // member initializers are attached. const Type *NewCtorType; if (params == maxParams) NewCtorType = BaseCtorType; else { SmallVector Args; for (unsigned i = 0; i < params; ++i) { Args.push_back(BaseCtorType->getArgType(i)); } FunctionProtoType::ExtProtoInfo ExtInfo = BaseCtorType->getExtProtoInfo(); ExtInfo.Variadic = false; NewCtorType = Context.getFunctionType(BaseCtorType->getResultType(), Args.data(), params, ExtInfo) .getTypePtr(); } const Type *CanonicalNewCtorType = Context.getCanonicalType(NewCtorType); // Now that we have the type, first check if the class already has a // constructor with this signature. if (ExistingConstructors.count(CanonicalNewCtorType)) continue; // Then we check if we have already declared an inherited constructor // with this signature. std::pair result = InheritedConstructors.insert(std::make_pair( CanonicalNewCtorType, std::make_pair(CanonicalBase, (CXXConstructorDecl*)0))); if (!result.second) { // Already in the map. If it came from a different class, that's an // error. Not if it's from the same. CanQualType PreviousBase = result.first->second.first; if (CanonicalBase != PreviousBase) { const CXXConstructorDecl *PrevCtor = result.first->second.second; const CXXConstructorDecl *PrevBaseCtor = PrevCtor->getInheritedConstructor(); assert(PrevBaseCtor && "Conflicting constructor was not inherited"); Diag(UsingLoc, diag::err_using_decl_constructor_conflict); Diag(BaseCtor->getLocation(), diag::note_using_decl_constructor_conflict_current_ctor); Diag(PrevBaseCtor->getLocation(), diag::note_using_decl_constructor_conflict_previous_ctor); Diag(PrevCtor->getLocation(), diag::note_using_decl_constructor_conflict_previous_using); } continue; } // OK, we're there, now add the constructor. // C++0x [class.inhctor]p8: [...] that would be performed by a // user-written inline constructor [...] DeclarationNameInfo DNI(CreatedCtorName, UsingLoc); CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0), /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true, /*ImplicitlyDeclared=*/true, // FIXME: Due to a defect in the standard, we treat inherited // constructors as constexpr even if that makes them ill-formed. /*Constexpr=*/BaseCtor->isConstexpr()); NewCtor->setAccess(BaseCtor->getAccess()); // Build up the parameter decls and add them. SmallVector ParamDecls; for (unsigned i = 0; i < params; ++i) { ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/0, BaseCtorType->getArgType(i), /*TInfo=*/0, SC_None, SC_None, /*DefaultArg=*/0)); } NewCtor->setParams(ParamDecls); NewCtor->setInheritedConstructor(BaseCtor); ClassDecl->addDecl(NewCtor); result.first->second.second = NewCtor; } } } } Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have // an exception-specification. ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; // Direct base-class destructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), BEnd = ClassDecl->bases_end(); B != BEnd; ++B) { if (B->isVirtual()) // Handled below. continue; if (const RecordType *BaseType = B->getType()->getAs()) ExceptSpec.CalledDecl(B->getLocStart(), LookupDestructor(cast(BaseType->getDecl()))); } // Virtual base-class destructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), BEnd = ClassDecl->vbases_end(); B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs()) ExceptSpec.CalledDecl(B->getLocStart(), LookupDestructor(cast(BaseType->getDecl()))); } // Field destructors. for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs()) ExceptSpec.CalledDecl(F->getLocation(), LookupDestructor(cast(RecordTy->getDecl()))); } return ExceptSpec; } CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // C++ [class.dtor]p2: // If a class has no user-declared destructor, a destructor is // declared implicitly. An implicitly-declared destructor is an // inline public member of its class. ImplicitExceptionSpecification Spec = ComputeDefaultedDtorExceptionSpec(ClassDecl); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); // Create the actual destructor declaration. QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI); CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXDestructorDecl *Destructor = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0, /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setDefaulted(); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); // Note that we have declared this destructor. ++ASTContext::NumImplicitDestructorsDeclared; // Introduce this destructor into its scope. if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(Destructor, S, false); ClassDecl->addDecl(Destructor); // This could be uniqued if it ever proves significant. Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); AddOverriddenMethods(ClassDecl, Destructor); if (ShouldDeleteSpecialMember(Destructor, CXXDestructor)) Destructor->setDeletedAsWritten(); return Destructor; } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor) { assert((Destructor->isDefaulted() && !Destructor->doesThisDeclarationHaveABody() && !Destructor->isDeleted()) && "DefineImplicitDestructor - call it for implicit default dtor"); CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); if (Destructor->isInvalidDecl()) return; ImplicitlyDefinedFunctionScope Scope(*this, Destructor); DiagnosticErrorTrap Trap(Diags); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXDestructor << Context.getTagDeclType(ClassDecl); Destructor->setInvalidDecl(); return; } SourceLocation Loc = Destructor->getLocation(); Destructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc)); Destructor->setImplicitlyDefined(true); Destructor->setUsed(); MarkVTableUsed(CurrentLocation, ClassDecl); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Destructor); } } +/// \brief Perform any semantic analysis which needs to be delayed until all +/// pending class member declarations have been parsed. +void Sema::ActOnFinishCXXMemberDecls() { + // Now we have parsed all exception specifications, determine the implicit + // exception specifications for destructors. + for (unsigned i = 0, e = DelayedDestructorExceptionSpecs.size(); + i != e; ++i) { + CXXDestructorDecl *Dtor = DelayedDestructorExceptionSpecs[i]; + AdjustDestructorExceptionSpec(Dtor->getParent(), Dtor, true); + } + DelayedDestructorExceptionSpecs.clear(); + + // Perform any deferred checking of exception specifications for virtual + // destructors. + for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size(); + i != e; ++i) { + const CXXDestructorDecl *Dtor = + DelayedDestructorExceptionSpecChecks[i].first; + assert(!Dtor->getParent()->isDependentType() && + "Should not ever add destructors of templates into the list."); + CheckOverridingFunctionExceptionSpec(Dtor, + DelayedDestructorExceptionSpecChecks[i].second); + } + DelayedDestructorExceptionSpecChecks.clear(); +} + void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, - CXXDestructorDecl *destructor) { + CXXDestructorDecl *destructor, + bool WasDelayed) { // C++11 [class.dtor]p3: // A declaration of a destructor that does not have an exception- // specification is implicitly considered to have the same exception- // specification as an implicit declaration. const FunctionProtoType *dtorType = destructor->getType()-> getAs(); - if (dtorType->hasExceptionSpec()) + if (!WasDelayed && dtorType->hasExceptionSpec()) return; ImplicitExceptionSpecification exceptSpec = ComputeDefaultedDtorExceptionSpec(classDecl); // Replace the destructor's type, building off the existing one. Fortunately, // the only thing of interest in the destructor type is its extended info. // The return and arguments are fixed. FunctionProtoType::ExtProtoInfo epi = dtorType->getExtProtoInfo(); epi.ExceptionSpecType = exceptSpec.getExceptionSpecType(); epi.NumExceptions = exceptSpec.size(); epi.Exceptions = exceptSpec.data(); QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi); destructor->setType(ty); + // If we can't compute the exception specification for this destructor yet + // (because it depends on an exception specification which we have not parsed + // yet), make a note that we need to try again when the class is complete. + if (epi.ExceptionSpecType == EST_Delayed) { + assert(!WasDelayed && "couldn't compute destructor exception spec"); + DelayedDestructorExceptionSpecs.push_back(destructor); + } + // FIXME: If the destructor has a body that could throw, and the newly created // spec doesn't allow exceptions, we should emit a warning, because this // change in behavior can break conforming C++03 programs at runtime. // However, we don't have a body yet, so it needs to be done somewhere else. } /// \brief Builds a statement that copies/moves the given entity from \p From to /// \c To. /// /// This routine is used to copy/move the members of a class with an /// implicitly-declared copy/move assignment operator. When the entities being /// copied are arrays, this routine builds for loops to copy them. /// /// \param S The Sema object used for type-checking. /// /// \param Loc The location where the implicit copy/move is being generated. /// /// \param T The type of the expressions being copied/moved. Both expressions /// must have this type. /// /// \param To The expression we are copying/moving to. /// /// \param From The expression we are copying/moving from. /// /// \param CopyingBaseSubobject Whether we're copying/moving a base subobject. /// Otherwise, it's a non-static member subobject. /// /// \param Copying Whether we're copying or moving. /// /// \param Depth Internal parameter recording the depth of the recursion. /// /// \returns A statement or a loop that copies the expressions. static StmtResult BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, Expr *To, Expr *From, bool CopyingBaseSubobject, bool Copying, unsigned Depth = 0) { // C++0x [class.copy]p28: // Each subobject is assigned in the manner appropriate to its type: // // - if the subobject is of class type, as if by a call to operator= with // the subobject as the object expression and the corresponding // subobject of x as a single function argument (as if by explicit // qualification; that is, ignoring any possible virtual overriding // functions in more derived classes); if (const RecordType *RecordTy = T->getAs()) { CXXRecordDecl *ClassDecl = cast(RecordTy->getDecl()); // Look for operator=. DeclarationName Name = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal); LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName); S.LookupQualifiedName(OpLookup, ClassDecl, false); // Filter out any result that isn't a copy/move-assignment operator. LookupResult::Filter F = OpLookup.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); if (CXXMethodDecl *Method = dyn_cast(D)) if (Method->isCopyAssignmentOperator() || (!Copying && Method->isMoveAssignmentOperator())) continue; F.erase(); } F.done(); // Suppress the protected check (C++ [class.protected]) for each of the // assignment operators we found. This strange dance is required when // we're assigning via a base classes's copy-assignment operator. To // ensure that we're getting the right base class subobject (without // ambiguities), we need to cast "this" to that subobject type; to // ensure that we don't go through the virtual call mechanism, we need // to qualify the operator= name with the base class (see below). However, // this means that if the base class has a protected copy assignment // operator, the protected member access check will fail. So, we // rewrite "protected" access to "public" access in this case, since we // know by construction that we're calling from a derived class. if (CopyingBaseSubobject) { for (LookupResult::iterator L = OpLookup.begin(), LEnd = OpLookup.end(); L != LEnd; ++L) { if (L.getAccess() == AS_protected) L.setAccess(AS_public); } } // Create the nested-name-specifier that will be used to qualify the // reference to operator=; this is required to suppress the virtual // call mechanism. CXXScopeSpec SS; const Type *CanonicalT = S.Context.getCanonicalType(T.getTypePtr()); SS.MakeTrivial(S.Context, NestedNameSpecifier::Create(S.Context, 0, false, CanonicalT), Loc); // Create the reference to operator=. ExprResult OpEqualRef = S.BuildMemberReferenceExpr(To, T, Loc, /*isArrow=*/false, SS, /*TemplateKWLoc=*/SourceLocation(), /*FirstQualifierInScope=*/0, OpLookup, /*TemplateArgs=*/0, /*SuppressQualifierCheck=*/true); if (OpEqualRef.isInvalid()) return StmtError(); // Build the call to the assignment operator. ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0, OpEqualRef.takeAs(), Loc, &From, 1, Loc); if (Call.isInvalid()) return StmtError(); return S.Owned(Call.takeAs()); } // - if the subobject is of scalar type, the built-in assignment // operator is used. const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T); if (!ArrayTy) { ExprResult Assignment = S.CreateBuiltinBinOp(Loc, BO_Assign, To, From); if (Assignment.isInvalid()) return StmtError(); return S.Owned(Assignment.takeAs()); } // - if the subobject is an array, each element is assigned, in the // manner appropriate to the element type; // Construct a loop over the array bounds, e.g., // // for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0) // // that will copy each of the array elements. QualType SizeType = S.Context.getSizeType(); // Create the iteration variable. IdentifierInfo *IterationVarName = 0; { SmallString<8> Str; llvm::raw_svector_ostream OS(Str); OS << "__i" << Depth; IterationVarName = &S.Context.Idents.get(OS.str()); } VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType, S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None, SC_None); // Initialize the iteration variable to zero. llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0); IterationVar->setInit(IntegerLiteral::Create(S.Context, Zero, SizeType, Loc)); // Create a reference to the iteration variable; we'll use this several // times throughout. Expr *IterationVarRef = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc).take(); assert(IterationVarRef && "Reference to invented variable cannot fail!"); Expr *IterationVarRefRVal = S.DefaultLvalueConversion(IterationVarRef).take(); assert(IterationVarRefRVal && "Conversion of invented variable cannot fail!"); // Create the DeclStmt that holds the iteration variable. Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc); // Create the comparison against the array bound. llvm::APInt Upper = ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType)); Expr *Comparison = new (S.Context) BinaryOperator(IterationVarRefRVal, IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), BO_NE, S.Context.BoolTy, VK_RValue, OK_Ordinary, Loc); // Create the pre-increment of the iteration variable. Expr *Increment = new (S.Context) UnaryOperator(IterationVarRef, UO_PreInc, SizeType, VK_LValue, OK_Ordinary, Loc); // Subscript the "from" and "to" expressions with the iteration variable. From = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(From, Loc, IterationVarRefRVal, Loc)); To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc, IterationVarRefRVal, Loc)); if (!Copying) // Cast to rvalue From = CastForMoving(S, From); // Build the copy/move for an individual element of the array. StmtResult Copy = BuildSingleCopyAssign(S, Loc, ArrayTy->getElementType(), To, From, CopyingBaseSubobject, Copying, Depth + 1); if (Copy.isInvalid()) return StmtError(); // Construct the loop that copies all elements of this array. return S.ActOnForStmt(Loc, Loc, InitStmt, S.MakeFullExpr(Comparison), 0, S.MakeFullExpr(Increment), Loc, Copy.take()); } std::pair Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) return std::make_pair(ImplicitExceptionSpecification(*this), false); // C++ [class.copy]p10: // If the class definition does not explicitly declare a copy // assignment operator, one is declared implicitly. // The implicitly-defined copy assignment operator for a class X // will have the form // // X& X::operator=(const X&) // // if bool HasConstCopyAssignment = true; // -- each direct base class B of X has a copy assignment operator // whose parameter is of type const B&, const volatile B& or B, // and for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); HasConstCopyAssignment && Base != BaseEnd; ++Base) { // We'll handle this below if (LangOpts.CPlusPlus0x && Base->isVirtual()) continue; assert(!Base->getType()->isDependentType() && "Cannot generate implicit members for class with dependent bases."); CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); - LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0, - &HasConstCopyAssignment); + HasConstCopyAssignment &= + (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, + false, 0); } // In C++11, the above citation has "or virtual" added if (LangOpts.CPlusPlus0x) { for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); HasConstCopyAssignment && Base != BaseEnd; ++Base) { assert(!Base->getType()->isDependentType() && "Cannot generate implicit members for class with dependent bases."); CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); - LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0, - &HasConstCopyAssignment); + HasConstCopyAssignment &= + (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, + false, 0); } } // -- for all the nonstatic data members of X that are of a class // type M (or array thereof), each such class type has a copy // assignment operator whose parameter is of type const M&, // const volatile M& or M. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); HasConstCopyAssignment && Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, false, 0, - &HasConstCopyAssignment); + HasConstCopyAssignment &= + (bool)LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, + false, 0); } } // Otherwise, the implicitly declared copy assignment operator will // have the form // // X& X::operator=(X&) // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] // It is unspecified whether or not an implicit copy assignment operator // attempts to deduplicate calls to assignment operators of virtual bases are // made. As such, this exception specification is effectively unspecified. // Based on a similar decision made for constness in C++0x, we're erring on // the side of assuming such calls to be made regardless of whether they // actually happen. ImplicitExceptionSpecification ExceptSpec(*this); unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; ++Base) { if (Base->isVirtual()) continue; CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, ArgQuals, false, 0)) ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); Base != BaseEnd; ++Base) { CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, ArgQuals, false, 0)) ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0)) ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign); } } return std::make_pair(ExceptSpec, HasConstCopyAssignment); } CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // Note: The following rules are largely analoguous to the copy // constructor rules. Note that virtual bases are not taken into account // for determining the argument type of the operator. Note also that // operators taking an object instead of a reference are allowed. ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl); QualType ArgType = Context.getTypeDeclType(ClassDecl); QualType RetType = Context.getLValueReferenceType(ArgType); if (Const) ArgType = ArgType.withConst(); ArgType = Context.getLValueReferenceType(ArgType); // An implicitly-declared copy assignment operator is an inline public // member of its class. FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(RetType, &ArgType, 1, EPI), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, /*isInline=*/true, /*isConstexpr=*/false, SourceLocation()); CopyAssignment->setAccess(AS_public); CopyAssignment->setDefaulted(); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassLoc, ClassLoc, /*Id=*/0, ArgType, /*TInfo=*/0, SC_None, SC_None, 0); CopyAssignment->setParams(FromParam); // Note that we have added this copy-assignment operator. ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(CopyAssignment, S, false); ClassDecl->addDecl(CopyAssignment); // C++0x [class.copy]p19: // .... If the class definition does not explicitly declare a copy // assignment operator, there is no user-declared move constructor, and // there is no user-declared move assignment operator, a copy assignment // operator is implicitly declared as defaulted. if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) CopyAssignment->setDeletedAsWritten(); AddOverriddenMethods(ClassDecl, CopyAssignment); return CopyAssignment; } void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *CopyAssignOperator) { assert((CopyAssignOperator->isDefaulted() && CopyAssignOperator->isOverloadedOperator() && CopyAssignOperator->getOverloadedOperator() == OO_Equal && !CopyAssignOperator->doesThisDeclarationHaveABody() && !CopyAssignOperator->isDeleted()) && "DefineImplicitCopyAssignment called for wrong function"); CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) { CopyAssignOperator->setInvalidDecl(); return; } CopyAssignOperator->setUsed(); ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator); DiagnosticErrorTrap Trap(Diags); // C++0x [class.copy]p30: // The implicitly-defined or explicitly-defaulted copy assignment operator // for a non-union class X performs memberwise copy assignment of its // subobjects. The direct base classes of X are assigned first, in the // order of their declaration in the base-specifier-list, and then the // immediate non-static data members of X are assigned, in the order in // which they were declared in the class definition. // The statements that form the synthesized function body. ASTOwningVector Statements(*this); // The parameter for the "other" object, which we are copying from. ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0); Qualifiers OtherQuals = Other->getType().getQualifiers(); QualType OtherRefType = Other->getType(); if (const LValueReferenceType *OtherRef = OtherRefType->getAs()) { OtherRefType = OtherRef->getPointeeType(); OtherQuals = OtherRefType.getQualifiers(); } // Our location for everything implicitly-generated. SourceLocation Loc = CopyAssignOperator->getLocation(); // Construct a reference to the "other" object. We'll be using this // throughout the generated ASTs. Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_LValue, Loc).take(); assert(OtherRef && "Reference to parameter cannot fail!"); // Construct the "this" pointer. We'll be using this throughout the generated // ASTs. Expr *This = ActOnCXXThis(Loc).takeAs(); assert(This && "Reference to this cannot fail!"); // Assign base classes. bool Invalid = false; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { // Form the assignment: // static_cast(this)->Base::operator=(static_cast(other)); QualType BaseType = Base->getType().getUnqualifiedType(); if (!BaseType->isRecordType()) { Invalid = true; continue; } CXXCastPath BasePath; BasePath.push_back(Base); // Construct the "from" expression, which is an implicit cast to the // appropriately-qualified base type. Expr *From = OtherRef; From = ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals), CK_UncheckedDerivedToBase, VK_LValue, &BasePath).take(); // Dereference "this". ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This); // Implicitly cast "this" to the appropriately-qualified base type. To = ImpCastExprToType(To.take(), Context.getCVRQualifiedType(BaseType, CopyAssignOperator->getTypeQualifiers()), CK_UncheckedDerivedToBase, VK_LValue, &BasePath); // Build the copy. StmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, To.get(), From, /*CopyingBaseSubobject=*/true, /*Copying=*/true); if (Copy.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); CopyAssignOperator->setInvalidDecl(); return; } // Success! Record the copy. Statements.push_back(Copy.takeAs()); } // \brief Reference to the __builtin_memcpy function. Expr *BuiltinMemCpyRef = 0; // \brief Reference to the __builtin_objc_memmove_collectable function. Expr *CollectableMemCpyRef = 0; // Assign non-static members. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { if (Field->isUnnamedBitfield()) continue; // Check for members of reference type; we can't copy those. if (Field->getType()->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } // Check for members of const-qualified, non-class type. QualType BaseType = Context.getBaseElementType(Field->getType()); if (!BaseType->getAs() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } // Suppress assigning zero-width bitfields. if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) continue; QualType FieldType = Field->getType().getNonReferenceType(); if (FieldType->isIncompleteArrayType()) { assert(ClassDecl->hasFlexibleArrayMember() && "Incomplete array type is not valid"); continue; } // Build references to the field in the object we're copying from and to. CXXScopeSpec SS; // Intentionally empty LookupResult MemberLookup(*this, Field->getDeclName(), Loc, LookupMemberName); MemberLookup.addDecl(*Field); MemberLookup.resolveKind(); ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType, Loc, /*IsArrow=*/false, SS, SourceLocation(), 0, MemberLookup, 0); ExprResult To = BuildMemberReferenceExpr(This, This->getType(), Loc, /*IsArrow=*/true, SS, SourceLocation(), 0, MemberLookup, 0); assert(!From.isInvalid() && "Implicit field reference cannot fail"); assert(!To.isInvalid() && "Implicit field reference cannot fail"); // If the field should be copied with __builtin_memcpy rather than via // explicit assignments, do so. This optimization only applies for arrays // of scalars and arrays of class type with trivial copy-assignment // operators. if (FieldType->isArrayType() && !FieldType.isVolatileQualified() && BaseType.hasTrivialAssignment(Context, /*Copying=*/true)) { // Compute the size of the memory buffer to be copied. QualType SizeType = Context.getSizeType(); llvm::APInt Size(Context.getTypeSize(SizeType), Context.getTypeSizeInChars(BaseType).getQuantity()); for (const ConstantArrayType *Array = Context.getAsConstantArrayType(FieldType); Array; Array = Context.getAsConstantArrayType(Array->getElementType())) { llvm::APInt ArraySize = Array->getSize().zextOrTrunc(Size.getBitWidth()); Size *= ArraySize; } // Take the address of the field references for "from" and "to". From = CreateBuiltinUnaryOp(Loc, UO_AddrOf, From.get()); To = CreateBuiltinUnaryOp(Loc, UO_AddrOf, To.get()); bool NeedsCollectableMemCpy = (BaseType->isRecordType() && BaseType->getAs()->getDecl()->hasObjectMember()); if (NeedsCollectableMemCpy) { if (!CollectableMemCpyRef) { // Create a reference to the __builtin_objc_memmove_collectable function. LookupResult R(*this, &Context.Idents.get("__builtin_objc_memmove_collectable"), Loc, LookupOrdinaryName); LookupName(R, TUScope, true); FunctionDecl *CollectableMemCpy = R.getAsSingle(); if (!CollectableMemCpy) { // Something went horribly wrong earlier, and we will have // complained about it. Invalid = true; continue; } CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, CollectableMemCpy->getType(), VK_LValue, Loc, 0).take(); assert(CollectableMemCpyRef && "Builtin reference cannot fail"); } } // Create a reference to the __builtin_memcpy builtin function. else if (!BuiltinMemCpyRef) { LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc, LookupOrdinaryName); LookupName(R, TUScope, true); FunctionDecl *BuiltinMemCpy = R.getAsSingle(); if (!BuiltinMemCpy) { // Something went horribly wrong earlier, and we will have complained // about it. Invalid = true; continue; } BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, BuiltinMemCpy->getType(), VK_LValue, Loc, 0).take(); assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); } ASTOwningVector CallArgs(*this); CallArgs.push_back(To.takeAs()); CallArgs.push_back(From.takeAs()); CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc)); ExprResult Call = ExprError(); if (NeedsCollectableMemCpy) Call = ActOnCallExpr(/*Scope=*/0, CollectableMemCpyRef, Loc, move_arg(CallArgs), Loc); else Call = ActOnCallExpr(/*Scope=*/0, BuiltinMemCpyRef, Loc, move_arg(CallArgs), Loc); assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); Statements.push_back(Call.takeAs()); continue; } // Build the copy of this field. StmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType, To.get(), From.get(), /*CopyingBaseSubobject=*/false, /*Copying=*/true); if (Copy.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); CopyAssignOperator->setInvalidDecl(); return; } // Success! Record the copy. Statements.push_back(Copy.takeAs()); } if (!Invalid) { // Add a "return *this;" ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This); StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; else { Statements.push_back(Return.takeAs()); if (Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; } } } if (Invalid) { CopyAssignOperator->setInvalidDecl(); return; } StmtResult Body; { CompoundScopeRAII CompoundScope(*this); Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), /*isStmtExpr=*/false); assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } CopyAssignOperator->setBody(Body.takeAs()); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyAssignOperator); } } Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; // C++0x [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] // It is unspecified whether or not an implicit move assignment operator // attempts to deduplicate calls to assignment operators of virtual bases are // made. As such, this exception specification is effectively unspecified. // Based on a similar decision made for constness in C++0x, we're erring on // the side of assuming such calls to be made regardless of whether they // actually happen. // Note that a move constructor is not implicitly declared when there are // virtual bases, but it can still be user-declared and explicitly defaulted. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; ++Base) { if (Base->isVirtual()) continue; CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, false, 0)) ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); Base != BaseEnd; ++Base) { CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, false, 0)) ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl, false, 0)) ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign); } } return ExceptSpec; } /// Determine whether the class type has any direct or indirect virtual base /// classes which have a non-trivial move assignment operator. static bool hasVirtualBaseWithNonTrivialMoveAssignment(Sema &S, CXXRecordDecl *ClassDecl) { for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); Base != BaseEnd; ++Base) { CXXRecordDecl *BaseClass = cast(Base->getType()->getAs()->getDecl()); // Try to declare the move assignment. If it would be deleted, then the // class does not have a non-trivial move assignment. if (BaseClass->needsImplicitMoveAssignment()) S.DeclareImplicitMoveAssignment(BaseClass); // If the class has both a trivial move assignment and a non-trivial move // assignment, hasTrivialMoveAssignment() is false. if (BaseClass->hasDeclaredMoveAssignment() && !BaseClass->hasTrivialMoveAssignment()) return true; } return false; } /// Determine whether the given type either has a move constructor or is /// trivially copyable. static bool hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) { Type = S.Context.getBaseElementType(Type); // FIXME: Technically, non-trivially-copyable non-class types, such as // reference types, are supposed to return false here, but that appears // to be a standard defect. CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl(); if (!ClassDecl) return true; if (Type.isTriviallyCopyableType(S.Context)) return true; if (IsConstructor) { if (ClassDecl->needsImplicitMoveConstructor()) S.DeclareImplicitMoveConstructor(ClassDecl); return ClassDecl->hasDeclaredMoveConstructor(); } if (ClassDecl->needsImplicitMoveAssignment()) S.DeclareImplicitMoveAssignment(ClassDecl); return ClassDecl->hasDeclaredMoveAssignment(); } /// Determine whether all non-static data members and direct or virtual bases /// of class \p ClassDecl have either a move operation, or are trivially /// copyable. static bool subobjectsHaveMoveOrTrivialCopy(Sema &S, CXXRecordDecl *ClassDecl, bool IsConstructor) { for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; ++Base) { if (Base->isVirtual()) continue; if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(), IsConstructor)) return false; } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); Base != BaseEnd; ++Base) { if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(), IsConstructor)) return false; } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { if (!hasMoveOrIsTriviallyCopyable(S, (*Field)->getType(), IsConstructor)) return false; } return true; } CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { // C++11 [class.copy]p20: // If the definition of a class X does not explicitly declare a move // assignment operator, one will be implicitly declared as defaulted // if and only if: // // - [first 4 bullets] assert(ClassDecl->needsImplicitMoveAssignment()); // [Checked after we build the declaration] // - the move assignment operator would not be implicitly defined as // deleted, // [DR1402]: // - X has no direct or indirect virtual base class with a non-trivial // move assignment operator, and // - each of X's non-static data members and direct or virtual base classes // has a type that either has a move assignment operator or is trivially // copyable. if (hasVirtualBaseWithNonTrivialMoveAssignment(*this, ClassDecl) || !subobjectsHaveMoveOrTrivialCopy(*this, ClassDecl,/*Constructor*/false)) { ClassDecl->setFailedImplicitMoveAssignment(); return 0; } // Note: The following rules are largely analoguous to the move // constructor rules. ImplicitExceptionSpecification Spec( ComputeDefaultedMoveAssignmentExceptionSpec(ClassDecl)); QualType ArgType = Context.getTypeDeclType(ClassDecl); QualType RetType = Context.getLValueReferenceType(ArgType); ArgType = Context.getRValueReferenceType(ArgType); // An implicitly-declared move assignment operator is an inline public // member of its class. FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(RetType, &ArgType, 1, EPI), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, /*isInline=*/true, /*isConstexpr=*/false, SourceLocation()); MoveAssignment->setAccess(AS_public); MoveAssignment->setDefaulted(); MoveAssignment->setImplicit(); MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment()); // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment, ClassLoc, ClassLoc, /*Id=*/0, ArgType, /*TInfo=*/0, SC_None, SC_None, 0); MoveAssignment->setParams(FromParam); // Note that we have added this copy-assignment operator. ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; // C++0x [class.copy]p9: // If the definition of a class X does not explicitly declare a move // assignment operator, one will be implicitly declared as defaulted if and // only if: // [...] // - the move assignment operator would not be implicitly defined as // deleted. if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) { // Cache this result so that we don't try to generate this over and over // on every lookup, leaking memory and wasting time. ClassDecl->setFailedImplicitMoveAssignment(); return 0; } if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(MoveAssignment, S, false); ClassDecl->addDecl(MoveAssignment); AddOverriddenMethods(ClassDecl, MoveAssignment); return MoveAssignment; } void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MoveAssignOperator) { assert((MoveAssignOperator->isDefaulted() && MoveAssignOperator->isOverloadedOperator() && MoveAssignOperator->getOverloadedOperator() == OO_Equal && !MoveAssignOperator->doesThisDeclarationHaveABody() && !MoveAssignOperator->isDeleted()) && "DefineImplicitMoveAssignment called for wrong function"); CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent(); if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) { MoveAssignOperator->setInvalidDecl(); return; } MoveAssignOperator->setUsed(); ImplicitlyDefinedFunctionScope Scope(*this, MoveAssignOperator); DiagnosticErrorTrap Trap(Diags); // C++0x [class.copy]p28: // The implicitly-defined or move assignment operator for a non-union class // X performs memberwise move assignment of its subobjects. The direct base // classes of X are assigned first, in the order of their declaration in the // base-specifier-list, and then the immediate non-static data members of X // are assigned, in the order in which they were declared in the class // definition. // The statements that form the synthesized function body. ASTOwningVector Statements(*this); // The parameter for the "other" object, which we are move from. ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0); QualType OtherRefType = Other->getType()-> getAs()->getPointeeType(); assert(OtherRefType.getQualifiers() == 0 && "Bad argument type of defaulted move assignment"); // Our location for everything implicitly-generated. SourceLocation Loc = MoveAssignOperator->getLocation(); // Construct a reference to the "other" object. We'll be using this // throughout the generated ASTs. Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_LValue, Loc).take(); assert(OtherRef && "Reference to parameter cannot fail!"); // Cast to rvalue. OtherRef = CastForMoving(*this, OtherRef); // Construct the "this" pointer. We'll be using this throughout the generated // ASTs. Expr *This = ActOnCXXThis(Loc).takeAs(); assert(This && "Reference to this cannot fail!"); // Assign base classes. bool Invalid = false; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { // Form the assignment: // static_cast(this)->Base::operator=(static_cast(other)); QualType BaseType = Base->getType().getUnqualifiedType(); if (!BaseType->isRecordType()) { Invalid = true; continue; } CXXCastPath BasePath; BasePath.push_back(Base); // Construct the "from" expression, which is an implicit cast to the // appropriately-qualified base type. Expr *From = OtherRef; From = ImpCastExprToType(From, BaseType, CK_UncheckedDerivedToBase, VK_XValue, &BasePath).take(); // Dereference "this". ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This); // Implicitly cast "this" to the appropriately-qualified base type. To = ImpCastExprToType(To.take(), Context.getCVRQualifiedType(BaseType, MoveAssignOperator->getTypeQualifiers()), CK_UncheckedDerivedToBase, VK_LValue, &BasePath); // Build the move. StmtResult Move = BuildSingleCopyAssign(*this, Loc, BaseType, To.get(), From, /*CopyingBaseSubobject=*/true, /*Copying=*/false); if (Move.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); MoveAssignOperator->setInvalidDecl(); return; } // Success! Record the move. Statements.push_back(Move.takeAs()); } // \brief Reference to the __builtin_memcpy function. Expr *BuiltinMemCpyRef = 0; // \brief Reference to the __builtin_objc_memmove_collectable function. Expr *CollectableMemCpyRef = 0; // Assign non-static members. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { if (Field->isUnnamedBitfield()) continue; // Check for members of reference type; we can't move those. if (Field->getType()->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } // Check for members of const-qualified, non-class type. QualType BaseType = Context.getBaseElementType(Field->getType()); if (!BaseType->getAs() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; continue; } // Suppress assigning zero-width bitfields. if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) continue; QualType FieldType = Field->getType().getNonReferenceType(); if (FieldType->isIncompleteArrayType()) { assert(ClassDecl->hasFlexibleArrayMember() && "Incomplete array type is not valid"); continue; } // Build references to the field in the object we're copying from and to. CXXScopeSpec SS; // Intentionally empty LookupResult MemberLookup(*this, Field->getDeclName(), Loc, LookupMemberName); MemberLookup.addDecl(*Field); MemberLookup.resolveKind(); ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType, Loc, /*IsArrow=*/false, SS, SourceLocation(), 0, MemberLookup, 0); ExprResult To = BuildMemberReferenceExpr(This, This->getType(), Loc, /*IsArrow=*/true, SS, SourceLocation(), 0, MemberLookup, 0); assert(!From.isInvalid() && "Implicit field reference cannot fail"); assert(!To.isInvalid() && "Implicit field reference cannot fail"); assert(!From.get()->isLValue() && // could be xvalue or prvalue "Member reference with rvalue base must be rvalue except for reference " "members, which aren't allowed for move assignment."); // If the field should be copied with __builtin_memcpy rather than via // explicit assignments, do so. This optimization only applies for arrays // of scalars and arrays of class type with trivial move-assignment // operators. if (FieldType->isArrayType() && !FieldType.isVolatileQualified() && BaseType.hasTrivialAssignment(Context, /*Copying=*/false)) { // Compute the size of the memory buffer to be copied. QualType SizeType = Context.getSizeType(); llvm::APInt Size(Context.getTypeSize(SizeType), Context.getTypeSizeInChars(BaseType).getQuantity()); for (const ConstantArrayType *Array = Context.getAsConstantArrayType(FieldType); Array; Array = Context.getAsConstantArrayType(Array->getElementType())) { llvm::APInt ArraySize = Array->getSize().zextOrTrunc(Size.getBitWidth()); Size *= ArraySize; } // Take the address of the field references for "from" and "to". We // directly construct UnaryOperators here because semantic analysis // does not permit us to take the address of an xvalue. From = new (Context) UnaryOperator(From.get(), UO_AddrOf, Context.getPointerType(From.get()->getType()), VK_RValue, OK_Ordinary, Loc); To = new (Context) UnaryOperator(To.get(), UO_AddrOf, Context.getPointerType(To.get()->getType()), VK_RValue, OK_Ordinary, Loc); bool NeedsCollectableMemCpy = (BaseType->isRecordType() && BaseType->getAs()->getDecl()->hasObjectMember()); if (NeedsCollectableMemCpy) { if (!CollectableMemCpyRef) { // Create a reference to the __builtin_objc_memmove_collectable function. LookupResult R(*this, &Context.Idents.get("__builtin_objc_memmove_collectable"), Loc, LookupOrdinaryName); LookupName(R, TUScope, true); FunctionDecl *CollectableMemCpy = R.getAsSingle(); if (!CollectableMemCpy) { // Something went horribly wrong earlier, and we will have // complained about it. Invalid = true; continue; } CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, CollectableMemCpy->getType(), VK_LValue, Loc, 0).take(); assert(CollectableMemCpyRef && "Builtin reference cannot fail"); } } // Create a reference to the __builtin_memcpy builtin function. else if (!BuiltinMemCpyRef) { LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc, LookupOrdinaryName); LookupName(R, TUScope, true); FunctionDecl *BuiltinMemCpy = R.getAsSingle(); if (!BuiltinMemCpy) { // Something went horribly wrong earlier, and we will have complained // about it. Invalid = true; continue; } BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, BuiltinMemCpy->getType(), VK_LValue, Loc, 0).take(); assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); } ASTOwningVector CallArgs(*this); CallArgs.push_back(To.takeAs()); CallArgs.push_back(From.takeAs()); CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc)); ExprResult Call = ExprError(); if (NeedsCollectableMemCpy) Call = ActOnCallExpr(/*Scope=*/0, CollectableMemCpyRef, Loc, move_arg(CallArgs), Loc); else Call = ActOnCallExpr(/*Scope=*/0, BuiltinMemCpyRef, Loc, move_arg(CallArgs), Loc); assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); Statements.push_back(Call.takeAs()); continue; } // Build the move of this field. StmtResult Move = BuildSingleCopyAssign(*this, Loc, FieldType, To.get(), From.get(), /*CopyingBaseSubobject=*/false, /*Copying=*/false); if (Move.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); MoveAssignOperator->setInvalidDecl(); return; } // Success! Record the copy. Statements.push_back(Move.takeAs()); } if (!Invalid) { // Add a "return *this;" ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This); StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; else { Statements.push_back(Return.takeAs()); if (Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); Invalid = true; } } } if (Invalid) { MoveAssignOperator->setInvalidDecl(); return; } StmtResult Body; { CompoundScopeRAII CompoundScope(*this); Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), /*isStmtExpr=*/false); assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } MoveAssignOperator->setBody(Body.takeAs()); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveAssignOperator); } } std::pair Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) return std::make_pair(ImplicitExceptionSpecification(*this), false); // C++ [class.copy]p5: // The implicitly-declared copy constructor for a class X will // have the form // // X::X(const X&) // // if // FIXME: It ought to be possible to store this on the record. bool HasConstCopyConstructor = true; // -- each direct or virtual base class B of X has a copy // constructor whose first parameter is of type const B& or // const volatile B&, and for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); HasConstCopyConstructor && Base != BaseEnd; ++Base) { // Virtual bases are handled below. if (Base->isVirtual()) continue; CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); - LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const, - &HasConstCopyConstructor); + HasConstCopyConstructor &= + (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); HasConstCopyConstructor && Base != BaseEnd; ++Base) { CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); - LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const, - &HasConstCopyConstructor); + HasConstCopyConstructor &= + (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const); } // -- for all the nonstatic data members of X that are of a // class type M (or array thereof), each such class type // has a copy constructor whose first parameter is of type // const M& or const volatile M&. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); HasConstCopyConstructor && Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const, - &HasConstCopyConstructor); + HasConstCopyConstructor &= + (bool)LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const); } } // Otherwise, the implicitly declared copy constructor will have // the form // // X::X(X&) // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] ImplicitExceptionSpecification ExceptSpec(*this); unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; ++Base) { // Virtual bases are handled below. if (Base->isVirtual()) continue; CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); if (CXXConstructorDecl *CopyConstructor = LookupCopyingConstructor(BaseClassDecl, Quals)) ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); Base != BaseEnd; ++Base) { CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); if (CXXConstructorDecl *CopyConstructor = LookupCopyingConstructor(BaseClassDecl, Quals)) ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXConstructorDecl *CopyConstructor = LookupCopyingConstructor(FieldClassDecl, Quals)) ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor); } } return std::make_pair(ExceptSpec, HasConstCopyConstructor); } CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CXXRecordDecl *ClassDecl) { // C++ [class.copy]p4: // If the class definition does not explicitly declare a copy // constructor, one is declared implicitly. ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl); QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = ClassType; if (Const) ArgType = ArgType.withConst(); ArgType = Context.getLValueReferenceType(ArgType); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); // An implicitly-declared copy constructor is an inline public // member of its class. CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, /*isConstexpr=*/ClassDecl->defaultedCopyConstructorIsConstexpr() && getLangOpts().CPlusPlus0x); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); // Note that we have declared this constructor. ++ASTContext::NumImplicitCopyConstructorsDeclared; // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor, ClassLoc, ClassLoc, /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, SC_None, SC_None, 0); CopyConstructor->setParams(FromParam); if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(CopyConstructor, S, false); ClassDecl->addDecl(CopyConstructor); // C++11 [class.copy]p8: // ... If the class definition does not explicitly declare a copy // constructor, there is no user-declared move constructor, and there is no // user-declared move assignment operator, a copy constructor is implicitly // declared as defaulted. if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) CopyConstructor->setDeletedAsWritten(); return CopyConstructor; } void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *CopyConstructor) { assert((CopyConstructor->isDefaulted() && CopyConstructor->isCopyConstructor() && !CopyConstructor->doesThisDeclarationHaveABody() && !CopyConstructor->isDeleted()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor); DiagnosticErrorTrap Trap(Diags); if (SetCtorInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); CopyConstructor->setInvalidDecl(); } else { Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(), CopyConstructor->getLocation(), MultiStmtArg(*this, 0, 0), /*isStmtExpr=*/false) .takeAs()); CopyConstructor->setImplicitlyDefined(true); } CopyConstructor->setUsed(); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyConstructor); } } Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; // Direct base-class constructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), BEnd = ClassDecl->bases_end(); B != BEnd; ++B) { if (B->isVirtual()) // Handled below. continue; if (const RecordType *BaseType = B->getType()->getAs()) { CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } // Virtual base-class constructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), BEnd = ClassDecl->vbases_end(); B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs()) { CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } // Field constructors. for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs()) { CXXRecordDecl *FieldRecDecl = cast(RecordTy->getDecl()); CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. // In particular, the problem is that this function never gets called. It // might just be ill-formed because this function attempts to refer to // a deleted function here. if (Constructor) ExceptSpec.CalledDecl(F->getLocation(), Constructor); } } return ExceptSpec; } CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( CXXRecordDecl *ClassDecl) { // C++11 [class.copy]p9: // If the definition of a class X does not explicitly declare a move // constructor, one will be implicitly declared as defaulted if and only if: // // - [first 4 bullets] assert(ClassDecl->needsImplicitMoveConstructor()); // [Checked after we build the declaration] // - the move assignment operator would not be implicitly defined as // deleted, // [DR1402]: // - each of X's non-static data members and direct or virtual base classes // has a type that either has a move constructor or is trivially copyable. if (!subobjectsHaveMoveOrTrivialCopy(*this, ClassDecl, /*Constructor*/true)) { ClassDecl->setFailedImplicitMoveConstructor(); return 0; } ImplicitExceptionSpecification Spec( ComputeDefaultedMoveCtorExceptionSpec(ClassDecl)); QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = Context.getRValueReferenceType(ClassType); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); // C++0x [class.copy]p11: // An implicitly-declared copy/move constructor is an inline public // member of its class. CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, /*isConstexpr=*/ClassDecl->defaultedMoveConstructorIsConstexpr() && getLangOpts().CPlusPlus0x); MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor()); // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor, ClassLoc, ClassLoc, /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, SC_None, SC_None, 0); MoveConstructor->setParams(FromParam); // C++0x [class.copy]p9: // If the definition of a class X does not explicitly declare a move // constructor, one will be implicitly declared as defaulted if and only if: // [...] // - the move constructor would not be implicitly defined as deleted. if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) { // Cache this result so that we don't try to generate this over and over // on every lookup, leaking memory and wasting time. ClassDecl->setFailedImplicitMoveConstructor(); return 0; } // Note that we have declared this constructor. ++ASTContext::NumImplicitMoveConstructorsDeclared; if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(MoveConstructor, S, false); ClassDecl->addDecl(MoveConstructor); return MoveConstructor; } void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *MoveConstructor) { assert((MoveConstructor->isDefaulted() && MoveConstructor->isMoveConstructor() && !MoveConstructor->doesThisDeclarationHaveABody() && !MoveConstructor->isDeleted()) && "DefineImplicitMoveConstructor - call it for implicit move ctor"); CXXRecordDecl *ClassDecl = MoveConstructor->getParent(); assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor"); ImplicitlyDefinedFunctionScope Scope(*this, MoveConstructor); DiagnosticErrorTrap Trap(Diags); if (SetCtorInitializers(MoveConstructor, 0, 0, /*AnyErrors=*/false) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXMoveConstructor << Context.getTagDeclType(ClassDecl); MoveConstructor->setInvalidDecl(); } else { Sema::CompoundScopeRAII CompoundScope(*this); MoveConstructor->setBody(ActOnCompoundStmt(MoveConstructor->getLocation(), MoveConstructor->getLocation(), MultiStmtArg(*this, 0, 0), /*isStmtExpr=*/false) .takeAs()); MoveConstructor->setImplicitlyDefined(true); } MoveConstructor->setUsed(); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveConstructor); } } bool Sema::isImplicitlyDeleted(FunctionDecl *FD) { return FD->isDeleted() && (FD->isDefaulted() || FD->isImplicit()) && isa(FD); } /// \brief Mark the call operator of the given lambda closure type as "used". static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) { CXXMethodDecl *CallOperator = cast( *Lambda->lookup( S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first); CallOperator->setReferenced(); CallOperator->setUsed(); } void Sema::DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLocation, CXXConversionDecl *Conv) { CXXRecordDecl *Lambda = Conv->getParent(); // Make sure that the lambda call operator is marked used. markLambdaCallOperatorUsed(*this, Lambda); Conv->setUsed(); ImplicitlyDefinedFunctionScope Scope(*this, Conv); DiagnosticErrorTrap Trap(Diags); // Return the address of the __invoke function. DeclarationName InvokeName = &Context.Idents.get("__invoke"); CXXMethodDecl *Invoke = cast(*Lambda->lookup(InvokeName).first); Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(), VK_LValue, Conv->getLocation()).take(); assert(FunctionRef && "Can't refer to __invoke function?"); Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take(); Conv->setBody(new (Context) CompoundStmt(Context, &Return, 1, Conv->getLocation(), Conv->getLocation())); // Fill in the __invoke function with a dummy implementation. IR generation // will fill in the actual details. Invoke->setUsed(); Invoke->setReferenced(); Invoke->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(), Conv->getLocation())); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); L->CompletedImplicitDefinition(Invoke); } } void Sema::DefineImplicitLambdaToBlockPointerConversion( SourceLocation CurrentLocation, CXXConversionDecl *Conv) { Conv->setUsed(); ImplicitlyDefinedFunctionScope Scope(*this, Conv); DiagnosticErrorTrap Trap(Diags); // Copy-initialize the lambda object as needed to capture it. Expr *This = ActOnCXXThis(CurrentLocation).take(); Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).take(); ExprResult BuildBlock = BuildBlockForLambdaConversion(CurrentLocation, Conv->getLocation(), Conv, DerefThis); // If we're not under ARC, make sure we still get the _Block_copy/autorelease // behavior. Note that only the general conversion function does this // (since it's unusable otherwise); in the case where we inline the // block literal, it has block literal lifetime semantics. if (!BuildBlock.isInvalid() && !getLangOpts().ObjCAutoRefCount) BuildBlock = ImplicitCastExpr::Create(Context, BuildBlock.get()->getType(), CK_CopyAndAutoreleaseBlockObject, BuildBlock.get(), 0, VK_RValue); if (BuildBlock.isInvalid()) { Diag(CurrentLocation, diag::note_lambda_to_block_conv); Conv->setInvalidDecl(); return; } // Create the return statement that returns the block from the conversion // function. StmtResult Return = ActOnReturnStmt(Conv->getLocation(), BuildBlock.get()); if (Return.isInvalid()) { Diag(CurrentLocation, diag::note_lambda_to_block_conv); Conv->setInvalidDecl(); return; } // Set the body of the conversion function. Stmt *ReturnS = Return.take(); Conv->setBody(new (Context) CompoundStmt(Context, &ReturnS, 1, Conv->getLocation(), Conv->getLocation())); // We're done; notify the mutation listener, if any. if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); } } /// \brief Determine whether the given list arguments contains exactly one /// "real" (non-default) argument. static bool hasOneRealArgument(MultiExprArg Args) { switch (Args.size()) { case 0: return false; default: if (!Args.get()[1]->isDefaultArgument()) return false; // fall through case 1: return !Args.get()[0]->isDefaultArgument(); } return false; } ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, bool HadMultipleCandidates, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { bool Elidable = false; // C++0x [class.copy]p34: // When certain criteria are met, an implementation is allowed to // omit the copy/move construction of a class object, even if the // copy/move constructor and/or destructor for the object have // side effects. [...] // - when a temporary class object that has not been bound to a // reference (12.2) would be copied/moved to a class object // with the same cv-unqualified type, the copy/move operation // can be omitted by constructing the temporary object // directly into the target of the omitted copy/move if (ConstructKind == CXXConstructExpr::CK_Complete && Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) { Expr *SubExpr = ((Expr **)ExprArgs.get())[0]; Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent()); } return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, Elidable, move(ExprArgs), HadMultipleCandidates, RequiresZeroInit, ConstructKind, ParenRange); } /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs, bool HadMultipleCandidates, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); for (specific_attr_iterator i = Constructor->specific_attr_begin(), e = Constructor->specific_attr_end(); i != e; ++i) { const NonNullAttr *NonNull = *i; CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc); } MarkFunctionReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, HadMultipleCandidates, /*FIXME*/false, RequiresZeroInit, static_cast(ConstructKind), ParenRange)); } bool Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, MultiExprArg Exprs, bool HadMultipleCandidates) { // FIXME: Provide the correct paren SourceRange when available. ExprResult TempResult = BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor, move(Exprs), HadMultipleCandidates, false, CXXConstructExpr::CK_Complete, SourceRange()); if (TempResult.isInvalid()) return true; Expr *Temp = TempResult.takeAs(); CheckImplicitConversions(Temp, VD->getLocation()); MarkFunctionReferenced(VD->getLocation(), Constructor); Temp = MaybeCreateExprWithCleanups(Temp); VD->setInit(Temp); return false; } void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { if (VD->isInvalidDecl()) return; CXXRecordDecl *ClassDecl = cast(Record->getDecl()); if (ClassDecl->isInvalidDecl()) return; if (ClassDecl->hasIrrelevantDestructor()) return; if (ClassDecl->isDependentContext()) return; CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); MarkFunctionReferenced(VD->getLocation(), Destructor); CheckDestructorAccess(VD->getLocation(), Destructor, PDiag(diag::err_access_dtor_var) << VD->getDeclName() << VD->getType()); DiagnoseUseOfDecl(Destructor, VD->getLocation()); if (!VD->hasGlobalStorage()) return; // Emit warning for non-trivial dtor in global scope (a real global, // class-static, function-static). Diag(VD->getLocation(), diag::warn_exit_time_destructor); // TODO: this should be re-enabled for static locals by !CXAAtExit if (!VD->isStaticLocal()) Diag(VD->getLocation(), diag::warn_global_destructor); } /// \brief Given a constructor and the set of arguments provided for the /// constructor, convert the arguments and add any required default arguments /// to form a proper call to this constructor. /// /// \returns true if an error occurred, false otherwise. bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, SourceLocation Loc, ASTOwningVector &ConvertedArgs, bool AllowExplicit) { // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall. unsigned NumArgs = ArgsPtr.size(); Expr **Args = (Expr **)ArgsPtr.get(); const FunctionProtoType *Proto = Constructor->getType()->getAs(); assert(Proto && "Constructor without a prototype?"); unsigned NumArgsInProto = Proto->getNumArgs(); // If too few arguments are available, we'll fill in the rest with defaults. if (NumArgs < NumArgsInProto) ConvertedArgs.reserve(NumArgsInProto); else ConvertedArgs.reserve(NumArgs); VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; SmallVector AllArgs; bool Invalid = GatherArgumentsForCall(Loc, Constructor, Proto, 0, Args, NumArgs, AllArgs, CallType, AllowExplicit); ConvertedArgs.append(AllArgs.begin(), AllArgs.end()); DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size()); // FIXME: Missing call to CheckFunctionCall or equivalent return Invalid; } static inline bool CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, const FunctionDecl *FnDecl) { const DeclContext *DC = FnDecl->getDeclContext()->getRedeclContext(); if (isa(DC)) { return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_declared_in_namespace) << FnDecl->getDeclName(); } if (isa(DC) && FnDecl->getStorageClass() == SC_Static) { return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_declared_static) << FnDecl->getDeclName(); } return false; } static inline bool CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, CanQualType ExpectedResultType, CanQualType ExpectedFirstParamType, unsigned DependentParamTypeDiag, unsigned InvalidParamTypeDiag) { QualType ResultType = FnDecl->getType()->getAs()->getResultType(); // Check that the result type is not dependent. if (ResultType->isDependentType()) return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_dependent_result_type) << FnDecl->getDeclName() << ExpectedResultType; // Check that the result type is what we expect. if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_invalid_result_type) << FnDecl->getDeclName() << ExpectedResultType; // A function template must have at least 2 parameters. if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2) return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_template_too_few_parameters) << FnDecl->getDeclName(); // The function decl must have at least 1 parameter. if (FnDecl->getNumParams() == 0) return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_too_few_parameters) << FnDecl->getDeclName(); // Check the the first parameter type is not dependent. QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); if (FirstParamType->isDependentType()) return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag) << FnDecl->getDeclName() << ExpectedFirstParamType; // Check that the first parameter type is what we expect. if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() != ExpectedFirstParamType) return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag) << FnDecl->getDeclName() << ExpectedFirstParamType; return false; } static bool CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { // C++ [basic.stc.dynamic.allocation]p1: // A program is ill-formed if an allocation function is declared in a // namespace scope other than global scope or declared static in global // scope. if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl)) return true; CanQualType SizeTy = SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType()); // C++ [basic.stc.dynamic.allocation]p1: // The return type shall be void*. The first parameter shall have type // std::size_t. if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy, SizeTy, diag::err_operator_new_dependent_param_type, diag::err_operator_new_param_type)) return true; // C++ [basic.stc.dynamic.allocation]p1: // The first parameter shall not have an associated default argument. if (FnDecl->getParamDecl(0)->hasDefaultArg()) return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_default_arg) << FnDecl->getDeclName() << FnDecl->getParamDecl(0)->getDefaultArgRange(); return false; } static bool CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { // C++ [basic.stc.dynamic.deallocation]p1: // A program is ill-formed if deallocation functions are declared in a // namespace scope other than global scope or declared static in global // scope. if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl)) return true; // C++ [basic.stc.dynamic.deallocation]p2: // Each deallocation function shall return void and its first parameter // shall be void*. if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidTy, SemaRef.Context.VoidPtrTy, diag::err_operator_delete_dependent_param_type, diag::err_operator_delete_param_type)) return true; return false; } /// CheckOverloadedOperatorDeclaration - Check whether the declaration /// of this overloaded operator is well-formed. If so, returns false; /// otherwise, emits appropriate diagnostics and returns true. bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { assert(FnDecl && FnDecl->isOverloadedOperator() && "Expected an overloaded operator declaration"); OverloadedOperatorKind Op = FnDecl->getOverloadedOperator(); // C++ [over.oper]p5: // The allocation and deallocation functions, operator new, // operator new[], operator delete and operator delete[], are // described completely in 3.7.3. The attributes and restrictions // found in the rest of this subclause do not apply to them unless // explicitly stated in 3.7.3. if (Op == OO_Delete || Op == OO_Array_Delete) return CheckOperatorDeleteDeclaration(*this, FnDecl); if (Op == OO_New || Op == OO_Array_New) return CheckOperatorNewDeclaration(*this, FnDecl); // C++ [over.oper]p6: // An operator function shall either be a non-static member // function or be a non-member function and have at least one // parameter whose type is a class, a reference to a class, an // enumeration, or a reference to an enumeration. if (CXXMethodDecl *MethodDecl = dyn_cast(FnDecl)) { if (MethodDecl->isStatic()) return Diag(FnDecl->getLocation(), diag::err_operator_overload_static) << FnDecl->getDeclName(); } else { bool ClassOrEnumParam = false; for (FunctionDecl::param_iterator Param = FnDecl->param_begin(), ParamEnd = FnDecl->param_end(); Param != ParamEnd; ++Param) { QualType ParamType = (*Param)->getType().getNonReferenceType(); if (ParamType->isDependentType() || ParamType->isRecordType() || ParamType->isEnumeralType()) { ClassOrEnumParam = true; break; } } if (!ClassOrEnumParam) return Diag(FnDecl->getLocation(), diag::err_operator_overload_needs_class_or_enum) << FnDecl->getDeclName(); } // C++ [over.oper]p8: // An operator function cannot have default arguments (8.3.6), // except where explicitly stated below. // // Only the function-call operator allows default arguments // (C++ [over.call]p1). if (Op != OO_Call) { for (FunctionDecl::param_iterator Param = FnDecl->param_begin(); Param != FnDecl->param_end(); ++Param) { if ((*Param)->hasDefaultArg()) return Diag((*Param)->getLocation(), diag::err_operator_overload_default_arg) << FnDecl->getDeclName() << (*Param)->getDefaultArgRange(); } } static const bool OperatorUses[NUM_OVERLOADED_OPERATORS][3] = { { false, false, false } #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ , { Unary, Binary, MemberOnly } #include "clang/Basic/OperatorKinds.def" }; bool CanBeUnaryOperator = OperatorUses[Op][0]; bool CanBeBinaryOperator = OperatorUses[Op][1]; bool MustBeMemberOperator = OperatorUses[Op][2]; // C++ [over.oper]p8: // [...] Operator functions cannot have more or fewer parameters // than the number required for the corresponding operator, as // described in the rest of this subclause. unsigned NumParams = FnDecl->getNumParams() + (isa(FnDecl)? 1 : 0); if (Op != OO_Call && ((NumParams == 1 && !CanBeUnaryOperator) || (NumParams == 2 && !CanBeBinaryOperator) || (NumParams < 1) || (NumParams > 2))) { // We have the wrong number of parameters. unsigned ErrorKind; if (CanBeUnaryOperator && CanBeBinaryOperator) { ErrorKind = 2; // 2 -> unary or binary. } else if (CanBeUnaryOperator) { ErrorKind = 0; // 0 -> unary } else { assert(CanBeBinaryOperator && "All non-call overloaded operators are unary or binary!"); ErrorKind = 1; // 1 -> binary } return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be) << FnDecl->getDeclName() << NumParams << ErrorKind; } // Overloaded operators other than operator() cannot be variadic. if (Op != OO_Call && FnDecl->getType()->getAs()->isVariadic()) { return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic) << FnDecl->getDeclName(); } // Some operators must be non-static member functions. if (MustBeMemberOperator && !isa(FnDecl)) { return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be_member) << FnDecl->getDeclName(); } // C++ [over.inc]p1: // The user-defined function called operator++ implements the // prefix and postfix ++ operator. If this function is a member // function with no parameters, or a non-member function with one // parameter of class or enumeration type, it defines the prefix // increment operator ++ for objects of that type. If the function // is a member function with one parameter (which shall be of type // int) or a non-member function with two parameters (the second // of which shall be of type int), it defines the postfix // increment operator ++ for objects of that type. if ((Op == OO_PlusPlus || Op == OO_MinusMinus) && NumParams == 2) { ParmVarDecl *LastParam = FnDecl->getParamDecl(FnDecl->getNumParams() - 1); bool ParamIsInt = false; if (const BuiltinType *BT = LastParam->getType()->getAs()) ParamIsInt = BT->getKind() == BuiltinType::Int; if (!ParamIsInt) return Diag(LastParam->getLocation(), diag::err_operator_overload_post_incdec_must_be_int) << LastParam->getType() << (Op == OO_MinusMinus); } return false; } /// CheckLiteralOperatorDeclaration - Check whether the declaration /// of this literal operator function is well-formed. If so, returns /// false; otherwise, emits appropriate diagnostics and returns true. bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { if (isa(FnDecl)) { Diag(FnDecl->getLocation(), diag::err_literal_operator_outside_namespace) << FnDecl->getDeclName(); return true; } if (FnDecl->isExternC()) { Diag(FnDecl->getLocation(), diag::err_literal_operator_extern_c); return true; } bool Valid = false; // This might be the definition of a literal operator template. FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate(); // This might be a specialization of a literal operator template. if (!TpDecl) TpDecl = FnDecl->getPrimaryTemplate(); // template type operator "" name() is the only valid template // signature, and the only valid signature with no parameters. if (TpDecl) { if (FnDecl->param_size() == 0) { // Must have only one template parameter TemplateParameterList *Params = TpDecl->getTemplateParameters(); if (Params->size() == 1) { NonTypeTemplateParmDecl *PmDecl = cast(Params->getParam(0)); // The template parameter must be a char parameter pack. if (PmDecl && PmDecl->isTemplateParameterPack() && Context.hasSameType(PmDecl->getType(), Context.CharTy)) Valid = true; } } } else if (FnDecl->param_size()) { // Check the first parameter FunctionDecl::param_iterator Param = FnDecl->param_begin(); QualType T = (*Param)->getType().getUnqualifiedType(); // unsigned long long int, long double, and any character type are allowed // as the only parameters. if (Context.hasSameType(T, Context.UnsignedLongLongTy) || Context.hasSameType(T, Context.LongDoubleTy) || Context.hasSameType(T, Context.CharTy) || Context.hasSameType(T, Context.WCharTy) || Context.hasSameType(T, Context.Char16Ty) || Context.hasSameType(T, Context.Char32Ty)) { if (++Param == FnDecl->param_end()) Valid = true; goto FinishedParams; } // Otherwise it must be a pointer to const; let's strip those qualifiers. const PointerType *PT = T->getAs(); if (!PT) goto FinishedParams; T = PT->getPointeeType(); if (!T.isConstQualified() || T.isVolatileQualified()) goto FinishedParams; T = T.getUnqualifiedType(); // Move on to the second parameter; ++Param; // If there is no second parameter, the first must be a const char * if (Param == FnDecl->param_end()) { if (Context.hasSameType(T, Context.CharTy)) Valid = true; goto FinishedParams; } // const char *, const wchar_t*, const char16_t*, and const char32_t* // are allowed as the first parameter to a two-parameter function if (!(Context.hasSameType(T, Context.CharTy) || Context.hasSameType(T, Context.WCharTy) || Context.hasSameType(T, Context.Char16Ty) || Context.hasSameType(T, Context.Char32Ty))) goto FinishedParams; // The second and final parameter must be an std::size_t T = (*Param)->getType().getUnqualifiedType(); if (Context.hasSameType(T, Context.getSizeType()) && ++Param == FnDecl->param_end()) Valid = true; } // FIXME: This diagnostic is absolutely terrible. FinishedParams: if (!Valid) { Diag(FnDecl->getLocation(), diag::err_literal_operator_params) << FnDecl->getDeclName(); return true; } // A parameter-declaration-clause containing a default argument is not // equivalent to any of the permitted forms. for (FunctionDecl::param_iterator Param = FnDecl->param_begin(), ParamEnd = FnDecl->param_end(); Param != ParamEnd; ++Param) { if ((*Param)->hasDefaultArg()) { Diag((*Param)->getDefaultArgRange().getBegin(), diag::err_literal_operator_default_argument) << (*Param)->getDefaultArgRange(); break; } } StringRef LiteralName = FnDecl->getDeclName().getCXXLiteralIdentifier()->getName(); if (LiteralName[0] != '_') { // C++11 [usrlit.suffix]p1: // Literal suffix identifiers that do not start with an underscore // are reserved for future standardization. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved); } return false; } /// ActOnStartLinkageSpecification - Parsed the beginning of a C++ /// linkage specification, including the language and (if present) /// the '{'. ExternLoc is the location of the 'extern', LangLoc is /// the location of the language string literal, which is provided /// by Lang/StrSize. LBraceLoc, if valid, provides the location of /// the '{' brace. Otherwise, this linkage specification does not /// have any braces. Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, StringRef Lang, SourceLocation LBraceLoc) { LinkageSpecDecl::LanguageIDs Language; if (Lang == "\"C\"") Language = LinkageSpecDecl::lang_c; else if (Lang == "\"C++\"") Language = LinkageSpecDecl::lang_cxx; else { Diag(LangLoc, diag::err_bad_language); return 0; } // FIXME: Add all the various semantics of linkage specifications LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, ExternLoc, LangLoc, Language); CurContext->addDecl(D); PushDeclContext(S, D); return D; } /// ActOnFinishLinkageSpecification - Complete the definition of /// the C++ linkage specification LinkageSpec. If RBraceLoc is /// valid, it's the position of the closing '}' brace in a linkage /// specification that uses braces. Decl *Sema::ActOnFinishLinkageSpecification(Scope *S, Decl *LinkageSpec, SourceLocation RBraceLoc) { if (LinkageSpec) { if (RBraceLoc.isValid()) { LinkageSpecDecl* LSDecl = cast(LinkageSpec); LSDecl->setRBraceLoc(RBraceLoc); } PopDeclContext(); } return LinkageSpec; } /// \brief Perform semantic analysis for the variable declaration that /// occurs within a C++ catch clause, returning the newly-created /// variable. VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, SourceLocation Loc, IdentifierInfo *Name) { bool Invalid = false; QualType ExDeclType = TInfo->getType(); // Arrays and functions decay. if (ExDeclType->isArrayType()) ExDeclType = Context.getArrayDecayedType(ExDeclType); else if (ExDeclType->isFunctionType()) ExDeclType = Context.getPointerType(ExDeclType); // C++ 15.3p1: The exception-declaration shall not denote an incomplete type. // The exception-declaration shall not denote a pointer or reference to an // incomplete type, other than [cv] void*. // N2844 forbids rvalue references. if (!ExDeclType->isDependentType() && ExDeclType->isRValueReferenceType()) { Diag(Loc, diag::err_catch_rvalue_ref); Invalid = true; } QualType BaseType = ExDeclType; int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference unsigned DK = diag::err_catch_incomplete; if (const PointerType *Ptr = BaseType->getAs()) { BaseType = Ptr->getPointeeType(); Mode = 1; DK = diag::err_catch_incomplete_ptr; } else if (const ReferenceType *Ref = BaseType->getAs()) { // For the purpose of error recovery, we treat rvalue refs like lvalue refs. BaseType = Ref->getPointeeType(); Mode = 2; DK = diag::err_catch_incomplete_ref; } if (!Invalid && (Mode == 0 || !BaseType->isVoidType()) && !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK)) Invalid = true; if (!Invalid && !ExDeclType->isDependentType() && RequireNonAbstractType(Loc, ExDeclType, diag::err_abstract_type_in_decl, AbstractVariableType)) Invalid = true; // Only the non-fragile NeXT runtime currently supports C++ catches // of ObjC types, and no runtime supports catching ObjC types by value. if (!Invalid && getLangOpts().ObjC1) { QualType T = ExDeclType; if (const ReferenceType *RT = T->getAs()) T = RT->getPointeeType(); if (T->isObjCObjectType()) { Diag(Loc, diag::err_objc_object_catch); Invalid = true; } else if (T->isObjCObjectPointerType()) { if (!getLangOpts().ObjCNonFragileABI) Diag(Loc, diag::warn_objc_pointer_cxx_catch_fragile); } } VarDecl *ExDecl = VarDecl::Create(Context, CurContext, StartLoc, Loc, Name, ExDeclType, TInfo, SC_None, SC_None); ExDecl->setExceptionVariable(true); // In ARC, infer 'retaining' for variables of retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(ExDecl)) Invalid = true; if (!Invalid && !ExDeclType->isDependentType()) { if (const RecordType *recordType = ExDeclType->getAs()) { // C++ [except.handle]p16: // The object declared in an exception-declaration or, if the // exception-declaration does not specify a name, a temporary (12.2) is // copy-initialized (8.5) from the exception object. [...] // The object is destroyed when the handler exits, after the destruction // of any automatic objects initialized within the handler. // // We just pretend to initialize the object with itself, then make sure // it can be destroyed later. QualType initType = ExDeclType; InitializedEntity entity = InitializedEntity::InitializeVariable(ExDecl); InitializationKind initKind = InitializationKind::CreateCopy(Loc, SourceLocation()); Expr *opaqueValue = new (Context) OpaqueValueExpr(Loc, initType, VK_LValue, OK_Ordinary); InitializationSequence sequence(*this, entity, initKind, &opaqueValue, 1); ExprResult result = sequence.Perform(*this, entity, initKind, MultiExprArg(&opaqueValue, 1)); if (result.isInvalid()) Invalid = true; else { // If the constructor used was non-trivial, set this as the // "initializer". CXXConstructExpr *construct = cast(result.take()); if (!construct->getConstructor()->isTrivial()) { Expr *init = MaybeCreateExprWithCleanups(construct); ExDecl->setInit(init); } // And make sure it's destructable. FinalizeVarWithDestructor(ExDecl, recordType); } } } if (Invalid) ExDecl->setInvalidDecl(); return ExDecl; } /// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch /// handler. Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); bool Invalid = D.isInvalidType(); // Check for unexpanded parameter packs. if (TInfo && DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_ExceptionType)) { TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, D.getIdentifierLoc()); Invalid = true; } IdentifierInfo *II = D.getIdentifier(); if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration)) { // The scope should be freshly made just for us. There is just no way // it contains any previous declaration. assert(!S->isDeclScope(PrevDecl)); if (PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); PrevDecl = 0; } } if (D.getCXXScopeSpec().isSet() && !Invalid) { Diag(D.getIdentifierLoc(), diag::err_qualified_catch_declarator) << D.getCXXScopeSpec().getRange(); Invalid = true; } VarDecl *ExDecl = BuildExceptionDeclaration(S, TInfo, D.getLocStart(), D.getIdentifierLoc(), D.getIdentifier()); if (Invalid) ExDecl->setInvalidDecl(); // Add the exception declaration into this scope. if (II) PushOnScopeChains(ExDecl, S); else CurContext->addDecl(ExDecl); ProcessDeclAttributes(S, ExDecl, D); return ExDecl; } Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *AssertMessageExpr_, SourceLocation RParenLoc) { StringLiteral *AssertMessage = cast(AssertMessageExpr_); if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) { // In a static_assert-declaration, the constant-expression shall be a // constant expression that can be contextually converted to bool. ExprResult Converted = PerformContextuallyConvertToBool(AssertExpr); if (Converted.isInvalid()) return 0; llvm::APSInt Cond; if (VerifyIntegerConstantExpression(Converted.get(), &Cond, PDiag(diag::err_static_assert_expression_is_not_constant), /*AllowFold=*/false).isInvalid()) return 0; if (!Cond) { llvm::SmallString<256> MsgBuffer; llvm::raw_svector_ostream Msg(MsgBuffer); AssertMessage->printPretty(Msg, Context, 0, getPrintingPolicy()); Diag(StaticAssertLoc, diag::err_static_assert_failed) << Msg.str() << AssertExpr->getSourceRange(); } } if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression)) return 0; Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc, AssertExpr, AssertMessage, RParenLoc); CurContext->addDecl(Decl); return Decl; } /// \brief Perform semantic analysis of the given friend type declaration. /// /// \returns A friend declaration that. FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc, SourceLocation FriendLoc, TypeSourceInfo *TSInfo) { assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); QualType T = TSInfo->getType(); SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange(); // C++03 [class.friend]p2: // An elaborated-type-specifier shall be used in a friend declaration // for a class.* // // * The class-key of the elaborated-type-specifier is required. if (!ActiveTemplateInstantiations.empty()) { // Do not complain about the form of friend template types during // template instantiation; we will already have complained when the // template was declared. } else if (!T->isElaboratedTypeSpecifier()) { // If we evaluated the type to a record type, suggest putting // a tag in front. if (const RecordType *RT = T->getAs()) { RecordDecl *RD = RT->getDecl(); std::string InsertionText = std::string(" ") + RD->getKindName(); Diag(TypeRange.getBegin(), getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_unelaborated_friend_type : diag::ext_unelaborated_friend_type) << (unsigned) RD->getTagKind() << T << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc), InsertionText); } else { Diag(FriendLoc, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_nonclass_type_friend : diag::ext_nonclass_type_friend) << T << SourceRange(FriendLoc, TypeRange.getEnd()); } } else if (T->getAs()) { Diag(FriendLoc, getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_enum_friend : diag::ext_enum_friend) << T << SourceRange(FriendLoc, TypeRange.getEnd()); } // C++0x [class.friend]p3: // If the type specifier in a friend declaration designates a (possibly // cv-qualified) class type, that class is declared as a friend; otherwise, // the friend declaration is ignored. // FIXME: C++0x has some syntactic restrictions on friend type declarations // in [class.friend]p3 that we do not implement. return FriendDecl::Create(Context, CurContext, Loc, TSInfo, FriendLoc); } /// Handle a friend tag declaration where the scope specifier was /// templated. Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, MultiTemplateParamsArg TempParamLists) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); bool isExplicitSpecialization = false; bool Invalid = false; if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS, TempParamLists.get(), TempParamLists.size(), /*friend*/ true, isExplicitSpecialization, Invalid)) { if (TemplateParams->size() > 0) { // This is a declaration of a class template. if (Invalid) return 0; return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, TemplateParams, AS_public, /*ModulePrivateLoc=*/SourceLocation(), TempParamLists.size() - 1, (TemplateParameterList**) TempParamLists.release()).take(); } else { // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) << TypeWithKeyword::getTagTypeKindName(Kind) << Name; isExplicitSpecialization = true; } } if (Invalid) return 0; bool isAllExplicitSpecializations = true; for (unsigned I = TempParamLists.size(); I-- > 0; ) { if (TempParamLists.get()[I]->size()) { isAllExplicitSpecializations = false; break; } } // FIXME: don't ignore attributes. // If it's explicit specializations all the way down, just forget // about the template header and build an appropriate non-templated // friend. TODO: for source fidelity, remember the headers. if (isAllExplicitSpecializations) { if (SS.isEmpty()) { bool Owned = false; bool IsDependent = false; return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, AS_public, /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned, IsDependent, /*ScopedEnumKWLoc=*/SourceLocation(), /*ScopedEnumUsesClassTag=*/false, /*UnderlyingType=*/TypeResult()); } NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); ElaboratedTypeKeyword Keyword = TypeWithKeyword::getKeywordForTagTypeKind(Kind); QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc, *Name, NameLoc); if (T.isNull()) return 0; TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); if (isa(T)) { DependentNameTypeLoc TL = cast(TSI->getTypeLoc()); TL.setElaboratedKeywordLoc(TagLoc); TL.setQualifierLoc(QualifierLoc); TL.setNameLoc(NameLoc); } else { ElaboratedTypeLoc TL = cast(TSI->getTypeLoc()); TL.setElaboratedKeywordLoc(TagLoc); TL.setQualifierLoc(QualifierLoc); cast(TL.getNamedTypeLoc()).setNameLoc(NameLoc); } FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc); Friend->setAccess(AS_public); CurContext->addDecl(Friend); return Friend; } assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?"); // Handle the case of a templated-scope friend class. e.g. // template class A::B; // FIXME: we don't support these right now. ElaboratedTypeKeyword ETK = TypeWithKeyword::getKeywordForTagTypeKind(Kind); QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name); TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); DependentNameTypeLoc TL = cast(TSI->getTypeLoc()); TL.setElaboratedKeywordLoc(TagLoc); TL.setQualifierLoc(SS.getWithLocInContext(Context)); TL.setNameLoc(NameLoc); FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc); Friend->setAccess(AS_public); Friend->setUnsupportedFriend(true); CurContext->addDecl(Friend); return Friend; } /// Handle a friend type declaration. This works in tandem with /// ActOnTag. /// /// Notes on friend class templates: /// /// We generally treat friend class declarations as if they were /// declaring a class. So, for example, the elaborated type specifier /// in a friend declaration is required to obey the restrictions of a /// class-head (i.e. no typedefs in the scope chain), template /// parameters are required to match up with simple template-ids, &c. /// However, unlike when declaring a template specialization, it's /// okay to refer to a template specialization without an empty /// template parameter declaration, e.g. /// friend class A::B; /// We permit this as a special case; if there are any template /// parameters present at all, require proper matching, i.e. /// template <> template friend class A::B; Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TempParams) { SourceLocation Loc = DS.getLocStart(); assert(DS.isFriendSpecified()); assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified); // Try to convert the decl specifier to a type. This works for // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. Declarator TheDeclarator(DS, Declarator::MemberContext); TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S); QualType T = TSI->getType(); if (TheDeclarator.isInvalidType()) return 0; if (DiagnoseUnexpandedParameterPack(Loc, TSI, UPPC_FriendDeclaration)) return 0; // This is definitely an error in C++98. It's probably meant to // be forbidden in C++0x, too, but the specification is just // poorly written. // // The problem is with declarations like the following: // template friend A::foo; // where deciding whether a class C is a friend or not now hinges // on whether there exists an instantiation of A that causes // 'foo' to equal C. There are restrictions on class-heads // (which we declare (by fiat) elaborated friend declarations to // be) that makes this tractable. // // FIXME: handle "template <> friend class A;", which // is possibly well-formed? Who even knows? if (TempParams.size() && !T->isElaboratedTypeSpecifier()) { Diag(Loc, diag::err_tagless_friend_type_template) << DS.getSourceRange(); return 0; } // C++98 [class.friend]p1: A friend of a class is a function // or class that is not a member of the class . . . // This is fixed in DR77, which just barely didn't make the C++03 // deadline. It's also a very silly restriction that seriously // affects inner classes and which nobody else seems to implement; // thus we never diagnose it, not even in -pedantic. // // But note that we could warn about it: it's always useless to // friend one of your own members (it's not, however, worthless to // friend a member of an arbitrary specialization of your template). Decl *D; if (unsigned NumTempParamLists = TempParams.size()) D = FriendTemplateDecl::Create(Context, CurContext, Loc, NumTempParamLists, TempParams.release(), TSI, DS.getFriendSpecLoc()); else D = CheckFriendTypeDecl(Loc, DS.getFriendSpecLoc(), TSI); if (!D) return 0; D->setAccess(AS_public); CurContext->addDecl(D); return D; } Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParams) { const DeclSpec &DS = D.getDeclSpec(); assert(DS.isFriendSpecified()); assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified); SourceLocation Loc = D.getIdentifierLoc(); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); // C++ [class.friend]p1 // A friend of a class is a function or class.... // Note that this sees through typedefs, which is intended. // It *doesn't* see through dependent types, which is correct // according to [temp.arg.type]p3: // If a declaration acquires a function type through a // type dependent on a template-parameter and this causes // a declaration that does not use the syntactic form of a // function declarator to have a function type, the program // is ill-formed. if (!TInfo->getType()->isFunctionType()) { Diag(Loc, diag::err_unexpected_friend); // It might be worthwhile to try to recover by creating an // appropriate declaration. return 0; } // 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. // - The name of the friend is not found by simple name lookup // until a matching declaration is provided in that namespace // scope (either before or after the class declaration granting // friendship). // - If a friend function is called, its name may be found by the // name lookup that considers functions from namespaces and // classes associated with the types of the function arguments. // - When looking for a prior declaration of a class or a function // declared as a friend, scopes outside the innermost enclosing // namespace scope are not considered. CXXScopeSpec &SS = D.getCXXScopeSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); assert(Name); // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(Loc, TInfo, UPPC_FriendDeclaration) || DiagnoseUnexpandedParameterPack(NameInfo, UPPC_FriendDeclaration) || DiagnoseUnexpandedParameterPack(SS, UPPC_FriendDeclaration)) return 0; // The context we found the declaration in, or in which we should // create the declaration. DeclContext *DC; Scope *DCScope = S; LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); // FIXME: there are different rules in local classes // There are four cases here. // - There's no scope specifier, in which case we just go to the // appropriate scope and look for a function or function template // there as appropriate. // Recover from invalid scope qualifiers as if they just weren't there. if (SS.isInvalid() || !SS.isSet()) { // C++0x [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. // C++0x [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. For a friend function // declaration, if there is no prior declaration, the program is // ill-formed. bool isLocal = cast(CurContext)->isLocalClass(); bool isTemplateId = D.getName().getKind() == UnqualifiedId::IK_TemplateId; // Find the appropriate context according to the above. DC = CurContext; while (true) { // Skip class contexts. If someone can cite chapter and verse // for this behavior, that would be nice --- it's what GCC and // EDG do, and it seems like a reasonable intent, but the spec // really only says that checks for unqualified existing // declarations should stop at the nearest enclosing namespace, // not that they should only consider the nearest enclosing // namespace. while (DC->isRecord() || DC->isTransparentContext()) DC = DC->getParent(); LookupQualifiedName(Previous, DC); // TODO: decide what we think about using declarations. if (isLocal || !Previous.empty()) break; if (isTemplateId) { if (isa(DC)) break; } else { if (DC->isFileContext()) break; } DC = DC->getParent(); } // C++ [class.friend]p1: A friend of a class is a function or // class that is not a member of the class . . . // C++11 changes this for both friend types and functions. // Most C++ 98 compilers do seem to give an error here, so // we do, too. if (!Previous.empty() && DC->Equals(CurContext)) Diag(DS.getFriendSpecLoc(), getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_friend_is_member : diag::err_friend_is_member); DCScope = getScopeForDeclContext(S, DC); // C++ [class.friend]p6: // A function can be defined in a friend declaration of a class if and // only if the class is a non-local class (9.8), the function name is // unqualified, and the function has namespace scope. if (isLocal && D.isFunctionDefinition()) { Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class); } // - There's a non-dependent scope specifier, in which case we // compute it and do a previous lookup there for a function // or function template. } else if (!SS.getScopeRep()->isDependent()) { DC = computeDeclContext(SS); if (!DC) return 0; if (RequireCompleteDeclContext(SS, DC)) return 0; LookupQualifiedName(Previous, DC); // Ignore things found implicitly in the wrong scope. // TODO: better diagnostics for this case. Suggesting the right // qualified scope would be nice... LookupResult::Filter F = Previous.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); if (!DC->InEnclosingNamespaceSetOf( D->getDeclContext()->getRedeclContext())) F.erase(); } F.done(); if (Previous.empty()) { D.setInvalidType(); Diag(Loc, diag::err_qualified_friend_not_found) << Name << TInfo->getType(); return 0; } // C++ [class.friend]p1: A friend of a class is a function or // class that is not a member of the class . . . if (DC->Equals(CurContext)) Diag(DS.getFriendSpecLoc(), getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_friend_is_member : diag::err_friend_is_member); if (D.isFunctionDefinition()) { // C++ [class.friend]p6: // A function can be defined in a friend declaration of a class if and // only if the class is a non-local class (9.8), the function name is // unqualified, and the function has namespace scope. SemaDiagnosticBuilder DB = Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def); DB << SS.getScopeRep(); if (DC->isFileContext()) DB << FixItHint::CreateRemoval(SS.getRange()); SS.clear(); } // - There's a scope specifier that does not match any template // parameter lists, in which case we use some arbitrary context, // create a method or method template, and wait for instantiation. // - There's a scope specifier that does match some template // parameter lists, which we don't handle right now. } else { if (D.isFunctionDefinition()) { // C++ [class.friend]p6: // A function can be defined in a friend declaration of a class if and // only if the class is a non-local class (9.8), the function name is // unqualified, and the function has namespace scope. Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def) << SS.getScopeRep(); } DC = CurContext; assert(isa(DC) && "friend declaration not in class?"); } if (!DC->isRecord()) { // This implies that it has to be an operator or function. if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName || D.getName().getKind() == UnqualifiedId::IK_DestructorName || D.getName().getKind() == UnqualifiedId::IK_ConversionFunctionId) { Diag(Loc, diag::err_introducing_special_friend) << (D.getName().getKind() == UnqualifiedId::IK_ConstructorName ? 0 : D.getName().getKind() == UnqualifiedId::IK_DestructorName ? 1 : 2); return 0; } } // FIXME: This is an egregious hack to cope with cases where the scope stack // does not contain the declaration context, i.e., in an out-of-line // definition of a class. Scope FakeDCScope(S, Scope::DeclScope, Diags); if (!DCScope) { FakeDCScope.setEntity(DC); DCScope = &FakeDCScope; } bool AddToScope = true; NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous, move(TemplateParams), AddToScope); if (!ND) return 0; assert(ND->getDeclContext() == DC); assert(ND->getLexicalDeclContext() == CurContext); // Add the function declaration to the appropriate lookup tables, // adjusting the redeclarations list as necessary. We don't // want to do this yet if the friending class is dependent. // // Also update the scope-based lookup if the target context's // lookup context is in lexical scope. if (!CurContext->isDependentContext()) { DC = DC->getRedeclContext(); DC->makeDeclVisibleInContext(ND); if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false); } FriendDecl *FrD = FriendDecl::Create(Context, CurContext, D.getIdentifierLoc(), ND, DS.getFriendSpecLoc()); FrD->setAccess(AS_public); CurContext->addDecl(FrD); if (ND->isInvalidDecl()) FrD->setInvalidDecl(); else { FunctionDecl *FD; if (FunctionTemplateDecl *FTD = dyn_cast(ND)) FD = FTD->getTemplatedDecl(); else FD = cast(ND); // Mark templated-scope function declarations as unsupported. if (FD->getNumTemplateParameterLists()) FrD->setUnsupportedFriend(true); } return ND; } void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { AdjustDeclIfTemplate(Dcl); FunctionDecl *Fn = dyn_cast(Dcl); if (!Fn) { Diag(DelLoc, diag::err_deleted_non_function); return; } if (const FunctionDecl *Prev = Fn->getPreviousDecl()) { Diag(DelLoc, diag::err_deleted_decl_not_first); Diag(Prev->getLocation(), diag::note_previous_declaration); // If the declaration wasn't the first, we delete the function anyway for // recovery. } Fn->setDeletedAsWritten(); CXXMethodDecl *MD = dyn_cast(Dcl); if (!MD) return; // A deleted special member function is trivial if the corresponding // implicitly-declared function would have been. switch (getSpecialMember(MD)) { case CXXInvalid: break; case CXXDefaultConstructor: MD->setTrivial(MD->getParent()->hasTrivialDefaultConstructor()); break; case CXXCopyConstructor: MD->setTrivial(MD->getParent()->hasTrivialCopyConstructor()); break; case CXXMoveConstructor: MD->setTrivial(MD->getParent()->hasTrivialMoveConstructor()); break; case CXXCopyAssignment: MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment()); break; case CXXMoveAssignment: MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment()); break; case CXXDestructor: MD->setTrivial(MD->getParent()->hasTrivialDestructor()); break; } } void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { CXXMethodDecl *MD = dyn_cast(Dcl); if (MD) { if (MD->getParent()->isDependentType()) { MD->setDefaulted(); MD->setExplicitlyDefaulted(); return; } CXXSpecialMember Member = getSpecialMember(MD); if (Member == CXXInvalid) { Diag(DefaultLoc, diag::err_default_special_members); return; } MD->setDefaulted(); MD->setExplicitlyDefaulted(); // If this definition appears within the record, do the checking when // the record is complete. const FunctionDecl *Primary = MD; if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) // Find the uninstantiated declaration that actually had the '= default' // on it. MD->getTemplateInstantiationPattern()->isDefined(Primary); if (Primary == Primary->getCanonicalDecl()) return; switch (Member) { case CXXDefaultConstructor: { CXXConstructorDecl *CD = cast(MD); CheckExplicitlyDefaultedDefaultConstructor(CD); if (!CD->isInvalidDecl()) DefineImplicitDefaultConstructor(DefaultLoc, CD); break; } case CXXCopyConstructor: { CXXConstructorDecl *CD = cast(MD); CheckExplicitlyDefaultedCopyConstructor(CD); if (!CD->isInvalidDecl()) DefineImplicitCopyConstructor(DefaultLoc, CD); break; } case CXXCopyAssignment: { CheckExplicitlyDefaultedCopyAssignment(MD); if (!MD->isInvalidDecl()) DefineImplicitCopyAssignment(DefaultLoc, MD); break; } case CXXDestructor: { CXXDestructorDecl *DD = cast(MD); CheckExplicitlyDefaultedDestructor(DD); if (!DD->isInvalidDecl()) DefineImplicitDestructor(DefaultLoc, DD); break; } case CXXMoveConstructor: { CXXConstructorDecl *CD = cast(MD); CheckExplicitlyDefaultedMoveConstructor(CD); if (!CD->isInvalidDecl()) DefineImplicitMoveConstructor(DefaultLoc, CD); break; } case CXXMoveAssignment: { CheckExplicitlyDefaultedMoveAssignment(MD); if (!MD->isInvalidDecl()) DefineImplicitMoveAssignment(DefaultLoc, MD); break; } case CXXInvalid: llvm_unreachable("Invalid special member."); } } else { Diag(DefaultLoc, diag::err_default_special_members); } } static void SearchForReturnInStmt(Sema &Self, Stmt *S) { for (Stmt::child_range CI = S->children(); CI; ++CI) { Stmt *SubStmt = *CI; if (!SubStmt) continue; if (isa(SubStmt)) Self.Diag(SubStmt->getLocStart(), diag::err_return_in_constructor_handler); if (!isa(SubStmt)) SearchForReturnInStmt(Self, SubStmt); } } void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { for (unsigned I = 0, E = TryBlock->getNumHandlers(); I != E; ++I) { CXXCatchStmt *Handler = TryBlock->getHandler(I); SearchForReturnInStmt(*this, Handler); } } bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, const CXXMethodDecl *Old) { QualType NewTy = New->getType()->getAs()->getResultType(); QualType OldTy = Old->getType()->getAs()->getResultType(); if (Context.hasSameType(NewTy, OldTy) || NewTy->isDependentType() || OldTy->isDependentType()) return false; // Check if the return types are covariant QualType NewClassTy, OldClassTy; /// Both types must be pointers or references to classes. if (const PointerType *NewPT = NewTy->getAs()) { if (const PointerType *OldPT = OldTy->getAs()) { NewClassTy = NewPT->getPointeeType(); OldClassTy = OldPT->getPointeeType(); } } else if (const ReferenceType *NewRT = NewTy->getAs()) { if (const ReferenceType *OldRT = OldTy->getAs()) { if (NewRT->getTypeClass() == OldRT->getTypeClass()) { NewClassTy = NewRT->getPointeeType(); OldClassTy = OldRT->getPointeeType(); } } } // The return types aren't either both pointers or references to a class type. if (NewClassTy.isNull()) { Diag(New->getLocation(), diag::err_different_return_type_for_overriding_virtual_function) << New->getDeclName() << NewTy << OldTy; Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } // C++ [class.virtual]p6: // If the return type of D::f differs from the return type of B::f, the // class type in the return type of D::f shall be complete at the point of // declaration of D::f or shall be the class type D. if (const RecordType *RT = NewClassTy->getAs()) { if (!RT->isBeingDefined() && RequireCompleteType(New->getLocation(), NewClassTy, PDiag(diag::err_covariant_return_incomplete) << New->getDeclName())) return true; } if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) { // Check if the new class derives from the old class. if (!IsDerivedFrom(NewClassTy, OldClassTy)) { Diag(New->getLocation(), diag::err_covariant_return_not_derived) << New->getDeclName() << NewTy << OldTy; Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } // Check if we the conversion from derived to base is valid. if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, diag::err_covariant_return_inaccessible_base, diag::err_covariant_return_ambiguous_derived_to_base_conv, // FIXME: Should this point to the return type? New->getLocation(), SourceRange(), New->getDeclName(), 0)) { // FIXME: this note won't trigger for delayed access control // diagnostics, and it's impossible to get an undelayed error // here from access control during the original parse because // the ParsingDeclSpec/ParsingDeclarator are still in scope. Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } } // The qualifiers of the return types must be the same. if (NewTy.getLocalCVRQualifiers() != OldTy.getLocalCVRQualifiers()) { Diag(New->getLocation(), diag::err_covariant_return_type_different_qualifications) << New->getDeclName() << NewTy << OldTy; Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; }; // The new class type must have the same or less qualifiers as the old type. if (NewClassTy.isMoreQualifiedThan(OldClassTy)) { Diag(New->getLocation(), diag::err_covariant_return_type_class_type_more_qualified) << New->getDeclName() << NewTy << OldTy; Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; }; return false; } /// \brief Mark the given method pure. /// /// \param Method the method to be marked pure. /// /// \param InitRange the source range that covers the "0" initializer. bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) { SourceLocation EndLoc = InitRange.getEnd(); if (EndLoc.isValid()) Method->setRangeEnd(EndLoc); if (Method->isVirtual() || Method->getParent()->isDependentContext()) { Method->setPure(); return false; } if (!Method->isInvalidDecl()) Diag(Method->getLocation(), diag::err_non_virtual_pure) << Method->getDeclName() << InitRange; return true; } /// \brief Determine whether the given declaration is a static data member. static bool isStaticDataMember(Decl *D) { VarDecl *Var = dyn_cast_or_null(D); if (!Var) return false; return Var->isStaticDataMember(); } /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse /// an initializer for the out-of-line declaration 'Dcl'. The scope /// is a fresh scope pushed for just this purpose. /// /// 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 Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. if (D == 0 || D->isInvalidDecl()) return; // We should only get called for declarations with scope specifiers, like: // int foo::bar; assert(D->isOutOfLine()); EnterDeclaratorContext(S, D->getDeclContext()); // If we are parsing the initializer for a static data member, push a // new expression evaluation context that is associated with this static // data member. if (isStaticDataMember(D)) PushExpressionEvaluationContext(PotentiallyEvaluated, D); } /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an /// initializer for the out-of-line declaration 'D'. void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. if (D == 0 || D->isInvalidDecl()) return; if (isStaticDataMember(D)) PopExpressionEvaluationContext(); assert(D->isOutOfLine()); ExitDeclaratorContext(S); } /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a /// C++ if/switch/while/for statement. /// e.g: "if (int x = f()) {...}" DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { // C++ 6.4p2: // The declarator shall not specify a function or an array. // The type-specifier-seq shall not contain typedef and shall not declare a // new class or enumeration. assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class of condition decl."); Decl *Dcl = ActOnDeclarator(S, D); if (!Dcl) return true; if (isa(Dcl)) { // The declarator shall not specify a function. Diag(Dcl->getLocation(), diag::err_invalid_use_of_function_type) << D.getSourceRange(); return true; } return Dcl; } void Sema::LoadExternalVTableUses() { if (!ExternalSource) return; SmallVector VTables; ExternalSource->ReadUsedVTables(VTables); SmallVector NewUses; for (unsigned I = 0, N = VTables.size(); I != N; ++I) { llvm::DenseMap::iterator Pos = VTablesUsed.find(VTables[I].Record); // Even if a definition wasn't required before, it may be required now. if (Pos != VTablesUsed.end()) { if (!Pos->second && VTables[I].DefinitionRequired) Pos->second = true; continue; } VTablesUsed[VTables[I].Record] = VTables[I].DefinitionRequired; NewUses.push_back(VTableUse(VTables[I].Record, VTables[I].Location)); } VTableUses.insert(VTableUses.begin(), NewUses.begin(), NewUses.end()); } void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired) { // Ignore any vtable uses in unevaluated operands or for classes that do // not have a vtable. if (!Class->isDynamicClass() || Class->isDependentContext() || CurContext->isDependentContext() || ExprEvalContexts.back().Context == Unevaluated) return; // Try to insert this class into the map. LoadExternalVTableUses(); Class = cast(Class->getCanonicalDecl()); std::pair::iterator, bool> Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired)); if (!Pos.second) { // If we already had an entry, check to see if we are promoting this vtable // to required a definition. If so, we need to reappend to the VTableUses // list, since we may have already processed the first entry. if (DefinitionRequired && !Pos.first->second) { Pos.first->second = true; } else { // Otherwise, we can early exit. return; } } // Local classes need to have their virtual members marked // immediately. For all other classes, we mark their virtual members // at the end of the translation unit. if (Class->isLocalClass()) MarkVirtualMembersReferenced(Loc, Class); else VTableUses.push_back(std::make_pair(Class, Loc)); } bool Sema::DefineUsedVTables() { LoadExternalVTableUses(); if (VTableUses.empty()) return false; // Note: The VTableUses vector could grow as a result of marking // the members of a class as "used", so we check the size each // time through the loop and prefer indices (with are stable) to // iterators (which are not). bool DefinedAnything = false; for (unsigned I = 0; I != VTableUses.size(); ++I) { CXXRecordDecl *Class = VTableUses[I].first->getDefinition(); if (!Class) continue; SourceLocation Loc = VTableUses[I].second; // If this class has a key function, but that key function is // defined in another translation unit, we don't need to emit the // vtable even though we're using it. const CXXMethodDecl *KeyFunction = Context.getKeyFunction(Class); if (KeyFunction && !KeyFunction->hasBody()) { switch (KeyFunction->getTemplateSpecializationKind()) { case TSK_Undeclared: case TSK_ExplicitSpecialization: case TSK_ExplicitInstantiationDeclaration: // The key function is in another translation unit. continue; case TSK_ExplicitInstantiationDefinition: case TSK_ImplicitInstantiation: // We will be instantiating the key function. break; } } else if (!KeyFunction) { // If we have a class with no key function that is the subject // of an explicit instantiation declaration, suppress the // vtable; it will live with the explicit instantiation // definition. bool IsExplicitInstantiationDeclaration = Class->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration; for (TagDecl::redecl_iterator R = Class->redecls_begin(), REnd = Class->redecls_end(); R != REnd; ++R) { TemplateSpecializationKind TSK = cast(*R)->getTemplateSpecializationKind(); if (TSK == TSK_ExplicitInstantiationDeclaration) IsExplicitInstantiationDeclaration = true; else if (TSK == TSK_ExplicitInstantiationDefinition) { IsExplicitInstantiationDeclaration = false; break; } } if (IsExplicitInstantiationDeclaration) continue; } // Mark all of the virtual members of this class as referenced, so // that we can build a vtable. Then, tell the AST consumer that a // vtable for this class is required. DefinedAnything = true; MarkVirtualMembersReferenced(Loc, Class); CXXRecordDecl *Canonical = cast(Class->getCanonicalDecl()); Consumer.HandleVTable(Class, VTablesUsed[Canonical]); // Optionally warn if we're emitting a weak vtable. if (Class->getLinkage() == ExternalLinkage && Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { const FunctionDecl *KeyFunctionDef = 0; if (!KeyFunction || (KeyFunction->hasBody(KeyFunctionDef) && KeyFunctionDef->isInlined())) Diag(Class->getLocation(), Class->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition ? diag::warn_weak_template_vtable : diag::warn_weak_vtable) << Class; } } VTableUses.clear(); return DefinedAnything; } void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD) { for (CXXRecordDecl::method_iterator i = RD->method_begin(), e = RD->method_end(); i != e; ++i) { CXXMethodDecl *MD = *i; // C++ [basic.def.odr]p2: // [...] A virtual member function is used if it is not pure. [...] if (MD->isVirtual() && !MD->isPure()) MarkFunctionReferenced(Loc, MD); } // Only classes that have virtual bases need a VTT. if (RD->getNumVBases() == 0) return; for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); if (Base->getNumVBases() == 0) continue; MarkVirtualMembersReferenced(Loc, Base); } } /// SetIvarInitializers - This routine builds initialization ASTs for the /// Objective-C implementation whose ivars need be initialized. void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { if (!getLangOpts().CPlusPlus) return; if (ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) { SmallVector ivars; CollectIvarsToConstructOrDestruct(OID, ivars); if (ivars.empty()) return; SmallVector AllToInit; for (unsigned i = 0; i < ivars.size(); i++) { FieldDecl *Field = ivars[i]; if (Field->isInvalidDecl()) continue; CXXCtorInitializer *Member; InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); InitializationKind InitKind = InitializationKind::CreateDefault(ObjCImplementation->getLocation()); InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); ExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind, MultiExprArg()); MemberInit = MaybeCreateExprWithCleanups(MemberInit); // Note, MemberInit could actually come back empty if no initialization // is required (e.g., because it would call a trivial default constructor) if (!MemberInit.get() || MemberInit.isInvalid()) continue; Member = new (Context) CXXCtorInitializer(Context, Field, SourceLocation(), SourceLocation(), MemberInit.takeAs(), SourceLocation()); AllToInit.push_back(Member); // Be sure that the destructor is accessible and is marked as referenced. if (const RecordType *RecordTy = Context.getBaseElementType(Field->getType()) ->getAs()) { CXXRecordDecl *RD = cast(RecordTy->getDecl()); if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { MarkFunctionReferenced(Field->getLocation(), Destructor); CheckDestructorAccess(Field->getLocation(), Destructor, PDiag(diag::err_access_dtor_ivar) << Context.getBaseElementType(Field->getType())); } } } ObjCImplementation->setIvarInitializers(Context, AllToInit.data(), AllToInit.size()); } } static void DelegatingCycleHelper(CXXConstructorDecl* Ctor, llvm::SmallSet &Valid, llvm::SmallSet &Invalid, llvm::SmallSet &Current, Sema &S) { llvm::SmallSet::iterator CI = Current.begin(), CE = Current.end(); if (Ctor->isInvalidDecl()) return; const FunctionDecl *FNTarget = 0; CXXConstructorDecl *Target; // We ignore the result here since if we don't have a body, Target will be // null below. (void)Ctor->getTargetConstructor()->hasBody(FNTarget); Target = const_cast(cast_or_null(FNTarget)); CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(), // Avoid dereferencing a null pointer here. *TCanonical = Target ? Target->getCanonicalDecl() : 0; if (!Current.insert(Canonical)) return; // We know that beyond here, we aren't chaining into a cycle. if (!Target || !Target->isDelegatingConstructor() || Target->isInvalidDecl() || Valid.count(TCanonical)) { for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI) Valid.insert(*CI); Current.clear(); // We've hit a cycle. } else if (TCanonical == Canonical || Invalid.count(TCanonical) || Current.count(TCanonical)) { // If we haven't diagnosed this cycle yet, do so now. if (!Invalid.count(TCanonical)) { S.Diag((*Ctor->init_begin())->getSourceLocation(), diag::warn_delegating_ctor_cycle) << Ctor; // Don't add a note for a function delegating directo to itself. if (TCanonical != Canonical) S.Diag(Target->getLocation(), diag::note_it_delegates_to); CXXConstructorDecl *C = Target; while (C->getCanonicalDecl() != Canonical) { (void)C->getTargetConstructor()->hasBody(FNTarget); assert(FNTarget && "Ctor cycle through bodiless function"); C = const_cast(cast(FNTarget)); S.Diag(C->getLocation(), diag::note_which_delegates_to); } } for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI) Invalid.insert(*CI); Current.clear(); } else { DelegatingCycleHelper(Target, Valid, Invalid, Current, S); } } void Sema::CheckDelegatingCtorCycles() { llvm::SmallSet Valid, Invalid, Current; llvm::SmallSet::iterator CI = Current.begin(), CE = Current.end(); for (DelegatingCtorDeclsType::iterator I = DelegatingCtorDecls.begin(ExternalSource), E = DelegatingCtorDecls.end(); I != E; ++I) { DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); } for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI) (*CI)->setInvalidDecl(); } namespace { /// \brief AST visitor that finds references to the 'this' expression. class FindCXXThisExpr : public RecursiveASTVisitor { Sema &S; public: explicit FindCXXThisExpr(Sema &S) : S(S) { } bool VisitCXXThisExpr(CXXThisExpr *E) { S.Diag(E->getLocation(), diag::err_this_static_member_func) << E->isImplicit(); return false; } }; } bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) { TypeSourceInfo *TSInfo = Method->getTypeSourceInfo(); if (!TSInfo) return false; TypeLoc TL = TSInfo->getTypeLoc(); FunctionProtoTypeLoc *ProtoTL = dyn_cast(&TL); if (!ProtoTL) return false; // C++11 [expr.prim.general]p3: // [The expression this] shall not appear before the optional // cv-qualifier-seq and it shall not appear within the declaration of a // static member function (although its type and value category are defined // within a static member function as they are within a non-static member // function). [ Note: this is because declaration matching does not occur // until the complete declarator is known. - end note ] const FunctionProtoType *Proto = ProtoTL->getTypePtr(); FindCXXThisExpr Finder(*this); // If the return type came after the cv-qualifier-seq, check it now. if (Proto->hasTrailingReturn() && !Finder.TraverseTypeLoc(ProtoTL->getResultLoc())) return true; // Check the exception specification. if (checkThisInStaticMemberFunctionExceptionSpec(Method)) return true; return checkThisInStaticMemberFunctionAttributes(Method); } bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { TypeSourceInfo *TSInfo = Method->getTypeSourceInfo(); if (!TSInfo) return false; TypeLoc TL = TSInfo->getTypeLoc(); FunctionProtoTypeLoc *ProtoTL = dyn_cast(&TL); if (!ProtoTL) return false; const FunctionProtoType *Proto = ProtoTL->getTypePtr(); FindCXXThisExpr Finder(*this); switch (Proto->getExceptionSpecType()) { case EST_Uninstantiated: case EST_BasicNoexcept: case EST_Delayed: case EST_DynamicNone: case EST_MSAny: case EST_None: break; case EST_ComputedNoexcept: if (!Finder.TraverseStmt(Proto->getNoexceptExpr())) return true; case EST_Dynamic: for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), EEnd = Proto->exception_end(); E != EEnd; ++E) { if (!Finder.TraverseType(*E)) return true; } break; } return false; } bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { FindCXXThisExpr Finder(*this); // Check attributes. for (Decl::attr_iterator A = Method->attr_begin(), AEnd = Method->attr_end(); A != AEnd; ++A) { // FIXME: This should be emitted by tblgen. Expr *Arg = 0; ArrayRef Args; if (GuardedByAttr *G = dyn_cast(*A)) Arg = G->getArg(); else if (PtGuardedByAttr *G = dyn_cast(*A)) Arg = G->getArg(); else if (AcquiredAfterAttr *AA = dyn_cast(*A)) Args = ArrayRef(AA->args_begin(), AA->args_size()); else if (AcquiredBeforeAttr *AB = dyn_cast(*A)) Args = ArrayRef(AB->args_begin(), AB->args_size()); else if (ExclusiveLockFunctionAttr *ELF = dyn_cast(*A)) Args = ArrayRef(ELF->args_begin(), ELF->args_size()); else if (SharedLockFunctionAttr *SLF = dyn_cast(*A)) Args = ArrayRef(SLF->args_begin(), SLF->args_size()); else if (ExclusiveTrylockFunctionAttr *ETLF = dyn_cast(*A)) { Arg = ETLF->getSuccessValue(); Args = ArrayRef(ETLF->args_begin(), ETLF->args_size()); } else if (SharedTrylockFunctionAttr *STLF = dyn_cast(*A)) { Arg = STLF->getSuccessValue(); Args = ArrayRef(STLF->args_begin(), STLF->args_size()); } else if (UnlockFunctionAttr *UF = dyn_cast(*A)) Args = ArrayRef(UF->args_begin(), UF->args_size()); else if (LockReturnedAttr *LR = dyn_cast(*A)) Arg = LR->getArg(); else if (LocksExcludedAttr *LE = dyn_cast(*A)) Args = ArrayRef(LE->args_begin(), LE->args_size()); else if (ExclusiveLocksRequiredAttr *ELR = dyn_cast(*A)) Args = ArrayRef(ELR->args_begin(), ELR->args_size()); else if (SharedLocksRequiredAttr *SLR = dyn_cast(*A)) Args = ArrayRef(SLR->args_begin(), SLR->args_size()); if (Arg && !Finder.TraverseStmt(Arg)) return true; for (unsigned I = 0, N = Args.size(); I != N; ++I) { if (!Finder.TraverseStmt(Args[I])) return true; } } return false; } void Sema::checkExceptionSpecification(ExceptionSpecificationType EST, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr, llvm::SmallVectorImpl &Exceptions, FunctionProtoType::ExtProtoInfo &EPI) { Exceptions.clear(); EPI.ExceptionSpecType = EST; if (EST == EST_Dynamic) { Exceptions.reserve(DynamicExceptions.size()); for (unsigned ei = 0, ee = DynamicExceptions.size(); ei != ee; ++ei) { // FIXME: Preserve type source info. QualType ET = GetTypeFromParser(DynamicExceptions[ei]); SmallVector Unexpanded; collectUnexpandedParameterPacks(ET, Unexpanded); if (!Unexpanded.empty()) { DiagnoseUnexpandedParameterPacks(DynamicExceptionRanges[ei].getBegin(), UPPC_ExceptionType, Unexpanded); continue; } // Check that the type is valid for an exception spec, and // drop it if not. if (!CheckSpecifiedExceptionType(ET, DynamicExceptionRanges[ei])) Exceptions.push_back(ET); } EPI.NumExceptions = Exceptions.size(); EPI.Exceptions = Exceptions.data(); return; } if (EST == EST_ComputedNoexcept) { // If an error occurred, there's no expression here. if (NoexceptExpr) { assert((NoexceptExpr->isTypeDependent() || NoexceptExpr->getType()->getCanonicalTypeUnqualified() == Context.BoolTy) && "Parser should have made sure that the expression is boolean"); if (NoexceptExpr && DiagnoseUnexpandedParameterPack(NoexceptExpr)) { EPI.ExceptionSpecType = EST_BasicNoexcept; return; } if (!NoexceptExpr->isValueDependent()) NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, 0, PDiag(diag::err_noexcept_needs_constant_expression), /*AllowFold*/ false).take(); EPI.NoexceptExpr = NoexceptExpr; } return; - } -} - -void Sema::actOnDelayedExceptionSpecification(Decl *MethodD, - ExceptionSpecificationType EST, - SourceRange SpecificationRange, - ArrayRef DynamicExceptions, - ArrayRef DynamicExceptionRanges, - Expr *NoexceptExpr) { - if (!MethodD) - return; - - // Dig out the method we're referring to. - CXXMethodDecl *Method = 0; - if (FunctionTemplateDecl *FunTmpl = dyn_cast(MethodD)) - Method = dyn_cast(FunTmpl->getTemplatedDecl()); - else - Method = dyn_cast(MethodD); - - if (!Method) - return; - - // Dig out the prototype. This should never fail. - const FunctionProtoType *Proto - = dyn_cast(Method->getType()); - if (!Proto) - return; - - // Check the exception specification. - llvm::SmallVector Exceptions; - FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); - checkExceptionSpecification(EST, DynamicExceptions, DynamicExceptionRanges, - NoexceptExpr, Exceptions, EPI); - - // Rebuild the function type. - QualType T = Context.getFunctionType(Proto->getResultType(), - Proto->arg_type_begin(), - Proto->getNumArgs(), - EPI); - if (TypeSourceInfo *TSInfo = Method->getTypeSourceInfo()) { - // FIXME: When we get proper type location information for exceptions, - // we'll also have to rebuild the TypeSourceInfo. For now, we just patch - // up the TypeSourceInfo; - assert(TypeLoc::getFullDataSizeForType(T) - == TypeLoc::getFullDataSizeForType(Method->getType()) && - "TypeLoc size mismatch with delayed exception specification"); - TSInfo->overrideType(T); - } - - Method->setType(T); - - if (Method->isStatic()) - checkThisInStaticMemberFunctionExceptionSpec(Method); - - if (Method->isVirtual()) { - // Check overrides, which we previously had to delay. - for (CXXMethodDecl::method_iterator O = Method->begin_overridden_methods(), - OEnd = Method->end_overridden_methods(); - O != OEnd; ++O) - CheckOverridingFunctionExceptionSpec(Method, *O); } } /// IdentifyCUDATarget - Determine the CUDA compilation target for this function Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { // Implicitly declared functions (e.g. copy constructors) are // __host__ __device__ if (D->isImplicit()) return CFT_HostDevice; if (D->hasAttr()) return CFT_Global; if (D->hasAttr()) { if (D->hasAttr()) return CFT_HostDevice; else return CFT_Device; } return CFT_Host; } bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget, CUDAFunctionTarget CalleeTarget) { // CUDA B.1.1 "The __device__ qualifier declares a function that is... // Callable from the device only." if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device) return true; // CUDA B.1.2 "The __global__ qualifier declares a function that is... // Callable from the host only." // CUDA B.1.3 "The __host__ qualifier declares a function that is... // Callable from the host only." if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) && (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)) return true; if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) return true; return false; } Index: vendor/clang/dist/lib/Sema/SemaLookup.cpp =================================================================== --- vendor/clang/dist/lib/Sema/SemaLookup.cpp (revision 235808) +++ vendor/clang/dist/lib/Sema/SemaLookup.cpp (revision 235809) @@ -1,4077 +1,4060 @@ //===--------------------- 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/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/TypoCorrection.h" #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 "llvm/ADT/SetVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/edit_distance.h" #include "llvm/Support/ErrorHandling.h" #include #include #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 = static_cast(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 = static_cast(S->getEntity()); if (Ctx && Ctx->isFileContext()) { visit(Ctx, Ctx); } else if (!Ctx || Ctx->isFunctionOrMethod()) { Scope::udir_iterator I = S->using_directives_begin(), End = S->using_directives_end(); for (; I != End; ++I) 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)) 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)) 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) { DeclContext::udir_iterator I, End; for (llvm::tie(I, End) = DC->getUsingDirectives(); I != End; ++I) { UsingDirectiveDecl *UD = *I; DeclContext *NS = UD->getNominatedNamespace(); if (visited.insert(NS)) { addUsingDirective(UD, EffectiveDC); queue.push_back(NS); } } if (queue.empty()) return; DC = queue.back(); queue.pop_back(); } } // 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(); } std::pair getNamespacesFor(DeclContext *DC) const { return std::equal_range(begin(), end(), DC->getPrimaryContext(), UnqualUsingEntry::Comparator()); } }; } // 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: 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; } 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: IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using; break; case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; 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, SemaRef.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. if (!isForRedeclaration()) { switch (NameInfo.getName().getCXXOverloadedOperator()) { case OO_New: case OO_Delete: case OO_Array_New: case OO_Array_Delete: SemaRef.DeclareGlobalNewDelete(); break; default: break; } } } void LookupResult::sanityImpl() const { // Note that this function is never called by NDEBUG builds. See // LookupResult::sanity(). 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 != NULL) == (ResultKind == Ambiguous && (Ambiguity == AmbiguousBaseSubobjectTypes || Ambiguity == AmbiguousBaseSubobjects))); } // Necessary because CXXBasePaths is not complete in Sema.h void LookupResult::deletePaths(CXXBasePaths *Paths) { delete Paths; } static NamedDecl *getVisibleDecl(NamedDecl *D); NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { return getVisibleDecl(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::SmallPtrSet Unique; llvm::SmallPtrSet UniqueTypes; bool Ambiguous = false; bool HasTag = false, HasFunction = false, HasNonFunction = false; bool HasFunctionTemplate = false, HasUnresolved = false; unsigned UniqueTagIndex = 0; unsigned I = 0; while (I < N) { NamedDecl *D = Decls[I]->getUnderlyingDecl(); D = cast(D->getCanonicalDecl()); // 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)) { if (!TD->getDeclContext()->isRecord()) { QualType T = SemaRef.Context.getTypeDeclType(TD); if (!UniqueTypes.insert(SemaRef.Context.getCanonicalType(T))) { // The type is not unique; pull something off the back and continue // at this index. Decls[I] = Decls[--N]; continue; } } } if (!Unique.insert(D)) { // If it's not unique, pull something off the back (and // continue at this index). 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) Ambiguous = true; HasNonFunction = true; } 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 (HideTags && HasTag && !Ambiguous && (HasFunction || HasNonFunction || HasUnresolved)) { if (Decls[UniqueTagIndex]->getDeclContext()->getRedeclContext()->Equals( Decls[UniqueTagIndex? 0 : N-1]->getDeclContext()->getRedeclContext())) Decls[UniqueTagIndex] = Decls[--N]; else Ambiguous = true; } 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; DeclContext::lookup_iterator DI, DE; for (I = P.begin(), E = P.end(); I != E; ++I) for (llvm::tie(DI,DE) = I->Decls; 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); } } /// \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 this is a builtin on this (or all) targets, create the decl. if (unsigned BuiltinID = II->getBuiltinID()) { // In C++, we don't have any predefined library functions like // 'malloc'. Instead, we'll just error. if (S.getLangOpts().CPlusPlus && 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; } if (R.isForRedeclaration()) { // If we're redeclaring this function anyway, forget that // this was a builtin at all. S.Context.BuiltinInfo.ForgetBuiltin(BuiltinID, S.Context.Idents); } return false; } } } return false; } /// \brief Determine whether we can declare a special member function within /// the class at this point. static bool CanDeclareSpecialMemberFunction(ASTContext &Context, 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. if (const RecordType *RecordTy = Context.getTypeDeclType(Class)->getAs()) return !RecordTy->isBeingDefined(); return false; } void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { if (!CanDeclareSpecialMemberFunction(Context, 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->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); // If the copy assignment operator has not yet been declared, do so now. if (!Class->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(Class); if (getLangOpts().CPlusPlus0x) { // If the move constructor has not yet been declared, do so now. if (Class->needsImplicitMoveConstructor()) DeclareImplicitMoveConstructor(Class); // might not actually do it // If the move assignment operator has not yet been declared, do so now. if (Class->needsImplicitMoveAssignment()) DeclareImplicitMoveAssignment(Class); // might not actually do it } // If the destructor has not yet been declared, do so now. if (!Class->hasDeclaredDestructor()) 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, const DeclContext *DC) { if (!DC) return; switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: if (const CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getDefinition() && CanDeclareSpecialMemberFunction(S.Context, Record)) { CXXRecordDecl *Class = const_cast(Record); if (Record->needsImplicitDefaultConstructor()) S.DeclareImplicitDefaultConstructor(Class); if (!Record->hasDeclaredCopyConstructor()) S.DeclareImplicitCopyConstructor(Class); if (S.getLangOpts().CPlusPlus0x && Record->needsImplicitMoveConstructor()) S.DeclareImplicitMoveConstructor(Class); } break; case DeclarationName::CXXDestructorName: if (const CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getDefinition() && !Record->hasDeclaredDestructor() && CanDeclareSpecialMemberFunction(S.Context, 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(S.Context, Record)) { CXXRecordDecl *Class = const_cast(Record); if (!Record->hasDeclaredCopyAssignment()) S.DeclareImplicitCopyAssignment(Class); if (S.getLangOpts().CPlusPlus0x && Record->needsImplicitMoveAssignment()) S.DeclareImplicitMoveAssignment(Class); } } 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(), DC); // Perform lookup into this declaration context. DeclContext::lookup_const_iterator I, E; for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { NamedDecl *D = *I; 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; const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); for (UnresolvedSetImpl::iterator U = Unresolved->begin(), UEnd = Unresolved->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.getSema().Context, R.getNameLoc()); FunctionDecl *Specialization = 0; 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_Default); EPI.ExceptionSpecType = EST_None; EPI.NumExceptions = 0; QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), 0, 0, EPI); // Perform template argument deduction against the type that we would // expect the function to have. if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, 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. UnqualUsingDirectiveSet::const_iterator UI, UEnd; llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(NS); for (; UI != UEnd; ++UI) if (LookupDirect(S, R, UI->getNominatedNamespace())) Found = true; R.resolveKind(); return Found; } static bool isNamespaceOrTranslationUnitScope(Scope *S) { if (DeclContext *Ctx = static_cast(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 = static_cast(S->getEntity()); DeclContext *Lexical = 0; for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) { if (OuterS->getEntity()) { Lexical = static_cast(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); } bool Sema::CppLookupName(LookupResult &R, Scope *S) { assert(getLangOpts().CPlusPlus && "Can perform only C++ lookup"); DeclarationName Name = R.getLookupName(); // 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 = static_cast(PreS->getEntity())) DeclareImplicitMemberFunctionsWithName(*this, Name, 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 // } // } // DeclContext *OutsideOfTemplateParamDC = 0; for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { DeclContext *Ctx = static_cast(S->getEntity()); // 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)) { Found = true; R.addDecl(ND); } } if (Found) { R.resolveKind(); if (S->isClassScope()) if (CXXRecordDecl *Record = dyn_cast_or_null(Ctx)) R.setNamingClass(Record); return true; } 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 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 = 0; } if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; llvm::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; } // 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 (R.getLookupKind() == 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! UnqualUsingDirectiveSet UDirs; UDirs.visitScopeChain(Initial, S); UDirs.done(); // 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 = static_cast(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 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 = 0; } if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; llvm::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 && 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(); } /// \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 *getVisibleDecl(NamedDecl *D) { if (LookupResult::isVisible(D)) return D; for (Decl::redecl_iterator RD = D->redecls_begin(), RDEnd = D->redecls_end(); RD != RDEnd; ++RD) { if (NamedDecl *ND = dyn_cast(*RD)) { if (LookupResult::isVisible(ND)) return ND; } } return 0; } /// @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 Name The name of the entity that we are searching for. /// /// @param Loc If provided, the source location where we're performing /// name lookup. At present, this is only used to produce diagnostics when /// C library functions (like "malloc") are implicitly declared. /// /// @returns The result of name lookup, which includes zero or more /// declarations and possibly additional information used to diagnose /// ambiguities. 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() && static_cast(S->getEntity()) ->isTransparentContext())) S = S->getParent(); } unsigned IDNS = R.getIdentifierNamespace(); // 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 ((*I)->isInIdentifierNamespace(IDNS)) { 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())) continue; } else if (NameKind == LookupObjCImplicitSelfParam && !isa(*I)) continue; // If this declaration is module-private and it came from an AST // file, we can't see it. NamedDecl *D = R.isHiddenDeclarationVisible()? *I : getVisibleDecl(*I); if (!D) 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 = 0; // Compute the DeclContext, if we need it. DeclContext *DC = 0; 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 isn't in the right namespace, skip it. if (!(*LastI)->isInIdentifierNamespace(IDNS)) continue; D = R.isHiddenDeclarationVisible()? *LastI : getVisibleDecl(*LastI); if (D) R.addDecl(D); } 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_iterator I = StartDC->using_directives_begin(); DeclContext::udir_iterator E = StartDC->using_directives_end(); if (I == E) 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 (; I != E; ++I) { NamespaceDecl *ND = (*I)->getNominatedNamespace()->getOriginalNamespace(); if (Visited.insert(ND)) 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.back(); Queue.pop_back(); // 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 (llvm::tie(I,E) = ND->getUsingDirectives(); I != E; ++I) { NamespaceDecl *Nom = (*I)->getNominatedNamespace(); if (Visited.insert(Nom)) 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, void *Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); DeclarationName N = DeclarationName::getFromOpaquePtr(Name); Path.Decls = BaseRecord->lookup(N); return Path.Decls.first != Path.Decls.second; } /// \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!"); // Perform qualified name lookup into the 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 CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0; switch (R.getLookupKind()) { case LookupObjCImplicitSelfParam: case LookupOrdinaryName: case LookupMemberName: case LookupRedeclarationWithLinkage: BaseCallback = &CXXRecordDecl::FindOrdinaryMember; break; case LookupTagName: BaseCallback = &CXXRecordDecl::FindTagMember; break; case LookupAnyName: BaseCallback = &LookupAnyMember; 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; } if (!LookupRec->lookupInBases(BaseCallback, R.getLookupName().getAsOpaquePtr(), 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 // this lookup is ambiguous. if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) { CXXBasePaths::paths_iterator FirstPath = Paths.begin(); DeclContext::lookup_iterator FirstD = FirstPath->Decls.first; DeclContext::lookup_iterator CurrentD = Path->Decls.first; while (FirstD != FirstPath->Decls.second && CurrentD != Path->Decls.second) { if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() != (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl()) break; ++FirstD; ++CurrentD; } if (FirstD == FirstPath->Decls.second && CurrentD == Path->Decls.second) 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.first, Path->Decls.second)) 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. DeclContext::lookup_iterator I, E; for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) { NamedDecl *D = *I; AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess, D->getAccess()); R.addDecl(D, AS); } R.resolveKind(); return true; } /// @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. /// /// @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()) { 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 Produce a diagnostic describing the ambiguity that resulted /// from name lookup. /// /// @param Result The ambiguous name lookup result. /// /// @param Name The name of the entity that name lookup was /// searching for. /// /// @param NameLoc The location of the name within the source code. /// /// @param LookupRange A source range that provides more /// source-location information concerning the lookup itself. For /// example, this range might highlight a nested-name-specifier that /// precedes the name. /// /// @returns true bool 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.first; while (isa(*Found) && cast(*Found)->isStatic()) ++Found; Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); return true; } 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.first; if (DeclsPrinted.insert(D).second) Diag(D->getLocation(), diag::note_ambiguous_member_found); } return true; } case LookupResult::AmbiguousTagHiding: { Diag(NameLoc, diag::err_ambiguous_tag_hiding) << Name << LookupRange; llvm::SmallPtrSet TagDecls; LookupResult::iterator DI, DE = Result.end(); for (DI = Result.begin(); DI != DE; ++DI) if (TagDecl *TD = dyn_cast(*DI)) { TagDecls.insert(TD); Diag(TD->getLocation(), diag::note_hidden_tag); } for (DI = Result.begin(); DI != DE; ++DI) if (!isa(*DI)) Diag((*DI)->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(); return true; } case LookupResult::AmbiguousReference: { Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange; LookupResult::iterator DI = Result.begin(), DE = Result.end(); for (; DI != DE; ++DI) Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI; return true; } } llvm_unreachable("unknown ambiguity kind"); } namespace { struct AssociatedLookup { AssociatedLookup(Sema &S, Sema::AssociatedNamespaceSet &Namespaces, Sema::AssociatedClassSet &Classes) : S(S), Namespaces(Namespaces), Classes(Classes) { } Sema &S; Sema::AssociatedNamespaceSet &Namespaces; Sema::AssociatedClassSet &Classes; }; } 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: // [Note: non-type template arguments do not contribute to the set of // associated namespaces. ] break; case TemplateArgument::Pack: for (TemplateArgument::pack_iterator P = Arg.pack_begin(), PEnd = Arg.pack_end(); P != PEnd; ++P) 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. 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 (!Class->hasDefinition()) { // FIXME: we might need to instantiate templates here 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.back(); Bases.pop_back(); // Visit the base classes. for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(), BaseEnd = Class->bases_end(); Base != BaseEnd; ++Base) { 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 (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), ArgEnd = Proto->arg_type_end(); Arg != ArgEnd; ++Arg) Queue.push_back(Arg->getTypePtr()); // fallthrough } case Type::FunctionNoProto: { const FunctionType *FnType = cast(T); T = FnType->getResultType().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; // 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; } if (Queue.empty()) break; T = Queue.back(); Queue.pop_back(); } } /// \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(llvm::ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses) { AssociatedNamespaces.clear(); AssociatedClasses.clear(); AssociatedLookup Result(*this, 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 (UnresolvedSetIterator I = ULE->decls_begin(), E = ULE->decls_end(); I != E; ++I) { // Look through any using declarations to find the underlying function. NamedDecl *Fn = (*I)->getUnderlyingDecl(); FunctionDecl *FDecl = dyn_cast(Fn); if (!FDecl) FDecl = cast(Fn)->getTemplatedDecl(); // Add the classes and namespaces associated with the parameter // types and return type of this function. addAssociatedClassesAndNamespaces(Result, FDecl->getType()); } } } /// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is /// an acceptable non-member overloaded operator for a call whose /// arguments have types T1 (and, if non-empty, T2). This routine /// implements the check in C++ [over.match.oper]p3b2 concerning /// enumeration types. static bool IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, QualType T1, QualType T2, ASTContext &Context) { if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType())) return true; if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType())) return true; const FunctionProtoType *Proto = Fn->getType()->getAs(); if (Proto->getNumArgs() < 1) return false; if (T1->isEnumeralType()) { QualType ArgType = Proto->getArgType(0).getNonReferenceType(); if (Context.hasSameUnqualifiedType(T1, ArgType)) return true; } if (Proto->getNumArgs() < 2) return false; if (!T2.isNull() && T2->isEnumeralType()) { QualType ArgType = Proto->getArgType(1).getNonReferenceType(); if (Context.hasSameUnqualifiedType(T2, ArgType)) return true; } return false; } 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. However, if no operand has a class // type, only those non-member functions in the lookup set // that have a first parameter of type T1 or "reference to // (possibly cv-qualified) T1", when T1 is an enumeration // type, or (if there is a right operand) a second parameter // of type T2 or "reference to (possibly cv-qualified) T2", // when T2 is an enumeration type, are candidate functions. DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); LookupResult Operators(*this, OpName, SourceLocation(), LookupOperatorName); LookupName(Operators, S); assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous"); if (Operators.empty()) return; for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end(); Op != OpEnd; ++Op) { NamedDecl *Found = (*Op)->getUnderlyingDecl(); if (FunctionDecl *FD = dyn_cast(Found)) { if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD } else if (FunctionTemplateDecl *FunTmpl = dyn_cast(Found)) { // FIXME: friend operators? // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate, // later? if (!FunTmpl->getDeclContext()->isRecord()) Functions.addDecl(*Op, Op.getAccess()); } } } Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis) { RD = RD->getDefinition(); assert((RD && !RD->isBeingDefined()) && "doing special member lookup into record that isn't fully complete"); 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"); 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; SpecialMemberOverloadResult *Result = SpecialMemberCache.FindNodeOrInsertPos(ID, InsertPoint); // This was already cached if (Result) return Result; Result = BumpAlloc.Allocate(); Result = new (Result) SpecialMemberOverloadResult(ID); SpecialMemberCache.InsertNode(Result, InsertPoint); if (SM == CXXDestructor) { if (!RD->hasDeclaredDestructor()) DeclareImplicitDestructor(RD); CXXDestructorDecl *DD = RD->getDestructor(); assert(DD && "record without a destructor"); Result->setMethod(DD); Result->setKind(DD->isDeleted() ? SpecialMemberOverloadResult::NoMemberOrDeleted : - SpecialMemberOverloadResult::SuccessNonConst); + 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 = 0; 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->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(RD); if (getLangOpts().CPlusPlus0x && RD->needsImplicitMoveConstructor()) DeclareImplicitMoveConstructor(RD); } else { Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); if (!RD->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(RD); if (getLangOpts().CPlusPlus0x && RD->needsImplicitMoveAssignment()) DeclareImplicitMoveAssignment(RD); } - QualType ArgType = CanTy; 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. - ExprValueKind VK; if (SM == CXXCopyConstructor || SM == CXXCopyAssignment) VK = VK_LValue; else VK = VK_RValue; + } + OpaqueValueExpr FakeArg(SourceLocation(), ArgType, VK); + + if (SM != CXXDefaultConstructor) { NumArgs = 1; - Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType, VK); + Arg = &FakeArg; } // Create the object argument QualType ThisTy = CanTy; if (ConstThis) ThisTy.addConst(); if (VolatileThis) ThisTy.addVolatile(); Expr::Classification Classification = - (new (Context) OpaqueValueExpr(SourceLocation(), ThisTy, - RValueThis ? VK_RValue : VK_LValue))-> - Classify(Context); + OpaqueValueExpr(SourceLocation(), 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((SourceLocation())); DeclContext::lookup_iterator I, E; - SpecialMemberOverloadResult::Kind SuccessKind = - SpecialMemberOverloadResult::SuccessNonConst; llvm::tie(I, E) = RD->lookup(Name); assert((I != E) && "lookup for a constructor or assignment operator was empty"); for ( ; I != E; ++I) { Decl *Cand = *I; if (Cand->isInvalidDecl()) continue; if (UsingShadowDecl *U = dyn_cast(Cand)) { // FIXME: [namespace.udecl]p15 says that we should only consider a // using declaration here if it does not match a declaration in the // derived class. We do not implement this correctly in other cases // either. Cand = U->getTargetDecl(); if (Cand->isInvalidDecl()) continue; } if (CXXMethodDecl *M = dyn_cast(Cand)) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodCandidate(M, DeclAccessPair::make(M, AS_public), RD, ThisTy, Classification, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), llvm::makeArrayRef(&Arg, NumArgs), OCS, true); - - // Here we're looking for a const parameter to speed up creation of - // implicit copy methods. - if ((SM == CXXCopyAssignment && M->isCopyAssignmentOperator()) || - (SM == CXXCopyConstructor && - cast(M)->isCopyConstructor())) { - QualType ArgType = M->getType()->getAs()->getArgType(0); - if (!ArgType->isReferenceType() || - ArgType->getPointeeType().isConstQualified()) - SuccessKind = SpecialMemberOverloadResult::SuccessConst; - } } else if (FunctionTemplateDecl *Tmpl = dyn_cast(Cand)) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), RD, 0, ThisTy, Classification, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), 0, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); } else { assert(isa(Cand) && "illegal Kind of operator = Decl"); } } OverloadCandidateSet::iterator Best; switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) { case OR_Success: Result->setMethod(cast(Best->Function)); - Result->setKind(SuccessKind); + Result->setKind(SpecialMemberOverloadResult::Success); break; case OR_Deleted: Result->setMethod(cast(Best->Function)); Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); break; case OR_Ambiguous: Result->setMethod(0); Result->setKind(SpecialMemberOverloadResult::Ambiguous); break; case OR_No_Viable_Function: Result->setMethod(0); 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, - bool *ConstParamMatch) { + 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); - if (ConstParamMatch) - *ConstParamMatch = Result->hasConstParamMatch(); - return cast_or_null(Result->getMethod()); } /// \brief Look up the moving constructor for the given class. CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class) { SpecialMemberOverloadResult *Result = LookupSpecialMember(Class, CXXMoveConstructor, false, false, 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(Context, Class)) { if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); if (getLangOpts().CPlusPlus0x && 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, - bool *ConstParamMatch) { + 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); - - if (ConstParamMatch) - *ConstParamMatch = Result->hasConstParamMatch(); return Result->getMethod(); } /// \brief Look up the moving assignment operator for the given class. CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, bool RValueThis, unsigned ThisQuals) { assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment this"); SpecialMemberOverloadResult *Result = LookupSpecialMember(Class, CXXMoveAssignment, false, false, 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 AllowRawAndTemplate) { 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 FoundTemplate = false; bool FoundRaw = false; bool FoundExactMatch = false; while (F.hasNext()) { Decl *D = F.next(); if (UsingShadowDecl *USD = dyn_cast(D)) D = USD->getTargetDecl(); bool IsTemplate = isa(D); bool IsRaw = false; bool IsExactMatch = false; if (FunctionDecl *FD = dyn_cast(D)) { if (FD->getNumParams() == 1 && FD->getParamDecl(0)->getType()->getAs()) IsRaw = true; else { 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 (IsExactMatch) { FoundExactMatch = true; AllowRawAndTemplate = false; if (FoundRaw || FoundTemplate) { // Go through again and remove the raw and template decls we've // already found. F.restart(); FoundRaw = FoundTemplate = false; } } else if (AllowRawAndTemplate && (IsTemplate || IsRaw)) { FoundTemplate |= IsTemplate; FoundRaw |= IsRaw; } 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) { Decl *D = *I; if (UsingShadowDecl *USD = dyn_cast(D)) D = USD->getTargetDecl(); if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) D = FunTmpl->getTemplatedDecl(); NoteOverloadCandidate(cast(D)); } return LOLR_Error; } if (FoundRaw) return LOLR_Raw; if (FoundTemplate) return LOLR_Template; // 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()) << AllowRawAndTemplate; 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 == 0 || Old == New) { Old = New; return; } // Otherwise, decide which is a more recent redeclaration. FunctionDecl *OldFD, *NewFD; if (isa(New)) { OldFD = cast(Old)->getTemplatedDecl(); NewFD = cast(New)->getTemplatedDecl(); } else { OldFD = cast(Old); NewFD = cast(New); } 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, bool Operator, SourceLocation Loc, llvm::ArrayRef Args, ADLResult &Result, bool StdNamespaceIsAssociated) { // Find all of the associated namespaces and classes based on the // arguments we have. AssociatedNamespaceSet AssociatedNamespaces; AssociatedClassSet AssociatedClasses; FindAssociatedClassesAndNamespaces(Args, AssociatedNamespaces, AssociatedClasses); if (StdNamespaceIsAssociated && StdNamespace) AssociatedNamespaces.insert(getStdNamespace()); QualType T1, T2; if (Operator) { T1 = Args[0]->getType(); if (Args.size() >= 2) T2 = Args[1]->getType(); } // Try to complete all associated classes, in case they contain a // declaration of a friend function. for (AssociatedClassSet::iterator C = AssociatedClasses.begin(), CEnd = AssociatedClasses.end(); C != CEnd; ++C) RequireCompleteType(Loc, Context.getRecordType(*C), 0); // 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 (AssociatedNamespaceSet::iterator NS = AssociatedNamespaces.begin(), NSEnd = AssociatedNamespaces.end(); NS != NSEnd; ++NS) { // 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_iterator I, E; for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) { NamedDecl *D = *I; // 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_OrdinaryFriend) { DeclContext *LexDC = D->getLexicalDeclContext(); if (!AssociatedClasses.count(cast(LexDC))) continue; } if (isa(D)) D = cast(D)->getTargetDecl(); if (isa(D)) { if (Operator && !IsAcceptableNonMemberOperatorCandidate(cast(D), T1, T2, Context)) continue; } else if (!isa(D)) continue; Result.insert(D); } } } //---------------------------------------------------------------------------- // Search for all visible declarations. //---------------------------------------------------------------------------- VisibleDeclConsumer::~VisibleDeclConsumer() { } 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); } 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.push_back(ShadowMap()); } ~ShadowContextRAII() { Visible.ShadowMaps.pop_back(); } }; } // end anonymous namespace NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { // Look through using declarations. ND = ND->getUnderlyingDecl(); 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 (ShadowMapEntry::iterator I = Pos->second.begin(), IEnd = Pos->second.end(); I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. if ((*I)->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; // Protocols are in distinct namespaces from everything else. if ((((*I)->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) || (IDNS & Decl::IDNS_ObjCProtocol)) && (*I)->getIdentifierNamespace() != IDNS) continue; // Functions and function templates in the same scope overload // rather than hide. FIXME: Look for hiding based on function // signatures! if ((*I)->isFunctionOrFunctionTemplate() && ND->isFunctionOrFunctionTemplate() && SM == ShadowMaps.rbegin()) continue; // We've found a declaration that hides this one. return *I; } } return 0; } static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, bool QualifiedNameLookup, bool InBaseClass, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited) { if (!Ctx) return; // Make sure we don't visit the same context twice. if (Visited.visitedContext(Ctx->getPrimaryContext())) return; if (CXXRecordDecl *Class = dyn_cast(Ctx)) Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. for (DeclContext::all_lookups_iterator L = Ctx->lookups_begin(), LEnd = Ctx->lookups_end(); L != LEnd; ++L) { for (DeclContext::lookup_result R = *L; R.first != R.second; ++R.first) { if (NamedDecl *ND = dyn_cast(*R.first)) { if ((ND = Result.getAcceptableDecl(ND))) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); Visited.add(ND); } } } } // Traverse using directives for qualified name lookup. if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); DeclContext::udir_iterator I, E; for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) { LookupVisibleDecls((*I)->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } // Traverse the contexts of inherited C++ classes. if (CXXRecordDecl *Record = dyn_cast(Ctx)) { if (!Record->hasDefinition()) return; for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), BEnd = Record->bases_end(); B != BEnd; ++B) { QualType BaseType = B->getType(); // Don't look into dependent bases, because name lookup can't look // there anyway. if (BaseType->isDependentType()) continue; const RecordType *Record = BaseType->getAs(); if (!Record) continue; // 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(Record->getDecl(), Result, QualifiedNameLookup, true, Consumer, Visited); } } // Traverse the contexts of Objective-C classes. if (ObjCInterfaceDecl *IFace = dyn_cast(Ctx)) { // Traverse categories. for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category; Category = Category->getNextClassCategory()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Category, Result, QualifiedNameLookup, false, Consumer, Visited); } // Traverse protocols. for (ObjCInterfaceDecl::all_protocol_iterator I = IFace->all_referenced_protocol_begin(), E = IFace->all_referenced_protocol_end(); I != E; ++I) { 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 (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(), E = Protocol->protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } } else if (ObjCCategoryDecl *Category = dyn_cast(Ctx)) { for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(), E = Category->protocol_end(); I != E; ++I) { 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((DeclContext *)S->getEntity())) || ((DeclContext *)S->getEntity())->isFunctionOrMethod()) { // Walk through the declarations in this Scope. for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast(*D)) if ((ND = Result.getAcceptableDecl(ND))) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false); Visited.add(ND); } } } // FIXME: C++ [temp.local]p8 DeclContext *Entity = 0; 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 = (DeclContext *)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. UnqualUsingDirectiveSet::const_iterator UI, UEnd; llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); for (; UI != UEnd; ++UI) LookupVisibleDecls(const_cast(UI->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); 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) { LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); VisibleDeclsRecord Visited; if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited); } /// 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 = 0; 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 = 0; if (Res == 0) { // 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 //===----------------------------------------------------------------------===// namespace { typedef llvm::StringMap TypoResultsMap; typedef std::map TypoEditDistanceMap; static const unsigned MaxTypoDistanceResultSets = 5; class TypoCorrectionConsumer : public VisibleDeclConsumer { /// \brief The name written that is a typo in the source. StringRef Typo; /// \brief The results found that have the smallest edit distance /// found (so far) with the typo name. /// /// The pointer value being set to the current DeclContext indicates /// whether there is a keyword with this name. TypoEditDistanceMap BestResults; Sema &SemaRef; public: explicit TypoCorrectionConsumer(Sema &SemaRef, IdentifierInfo *Typo) : Typo(Typo->getName()), SemaRef(SemaRef) { } virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass); void FoundName(StringRef Name); void addKeywordResult(StringRef Keyword); void addName(StringRef Name, NamedDecl *ND, unsigned Distance, NestedNameSpecifier *NNS=NULL, bool isKeyword=false); void addCorrection(TypoCorrection Correction); typedef TypoResultsMap::iterator result_iterator; typedef TypoEditDistanceMap::iterator distance_iterator; distance_iterator begin() { return BestResults.begin(); } distance_iterator end() { return BestResults.end(); } void erase(distance_iterator I) { BestResults.erase(I); } unsigned size() const { return BestResults.size(); } bool empty() const { return BestResults.empty(); } TypoCorrection &operator[](StringRef Name) { return BestResults.begin()->second[Name]; } unsigned getBestEditDistance(bool Normalized) { if (BestResults.empty()) return (std::numeric_limits::max)(); unsigned BestED = BestResults.begin()->first; return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED; } }; } 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; FoundName(Name->getName()); } void TypoCorrectionConsumer::FoundName(StringRef Name) { // Use a simple length-based heuristic to determine the minimum possible // edit distance. If the minimum isn't good enough, bail out early. unsigned MinED = abs((int)Name.size() - (int)Typo.size()); if (MinED && Typo.size() / MinED < 3) return; // Compute an upper bound on the allowable edit distance, so that the // edit-distance algorithm can short-circuit. unsigned UpperBound = (Typo.size() + 2) / 3; // Compute the edit distance between the typo and the name of this // entity, and add the identifier to the list of results. addName(Name, NULL, Typo.edit_distance(Name, true, UpperBound)); } 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, NULL, Typo.edit_distance(Keyword), NULL, true); } void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND, unsigned Distance, NestedNameSpecifier *NNS, bool isKeyword) { TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, Distance); if (isKeyword) TC.makeKeyword(); addCorrection(TC); } void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); TypoResultsMap &Map = BestResults[Correction.getEditDistance(false)]; TypoCorrection &CurrentCorrection = Map[Name]; if (!CurrentCorrection || // FIXME: The following should be rolled up into an operator< on // TypoCorrection with a more principled definition. CurrentCorrection.isKeyword() < Correction.isKeyword() || Correction.getAsString(SemaRef.getLangOpts()) < CurrentCorrection.getAsString(SemaRef.getLangOpts())) CurrentCorrection = Correction; while (BestResults.size() > MaxTypoDistanceResultSets) erase(llvm::prior(BestResults.end())); } // 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 = NULL; 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: return; } if (II) Identifiers.push_back(II); } namespace { class SpecifierInfo { public: DeclContext* DeclCtx; NestedNameSpecifier* NameSpecifier; unsigned EditDistance; SpecifierInfo(DeclContext *Ctx, NestedNameSpecifier *NNS, unsigned ED) : DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {} }; typedef SmallVector DeclContextList; typedef SmallVector SpecifierInfoList; class NamespaceSpecifierSet { ASTContext &Context; DeclContextList CurContextChain; SmallVector CurContextIdentifiers; SmallVector CurNameSpecifierIdentifiers; bool isSorted; SpecifierInfoList Specifiers; llvm::SmallSetVector Distances; llvm::DenseMap DistanceMap; /// \brief Helper for building the list of DeclContexts between the current /// context and the top of the translation unit static DeclContextList BuildContextChain(DeclContext *Start); void SortNamespaces(); public: NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec) : Context(Context), CurContextChain(BuildContextChain(CurContext)), isSorted(true) { if (CurScopeSpec && CurScopeSpec->getScopeRep()) getNestedNameSpecifierIdentifiers(CurScopeSpec->getScopeRep(), CurNameSpecifierIdentifiers); // Build the list of identifiers that would be used for an absolute // (from the global context) NestedNameSpecifier refering to the current // context. for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), CEnd = CurContextChain.rend(); C != CEnd; ++C) { if (NamespaceDecl *ND = dyn_cast_or_null(*C)) CurContextIdentifiers.push_back(ND->getIdentifier()); } } /// \brief Add the namespace to the set, computing the corresponding /// NestedNameSpecifier and its distance in the process. void AddNamespace(NamespaceDecl *ND); typedef SpecifierInfoList::iterator iterator; iterator begin() { if (!isSorted) SortNamespaces(); return Specifiers.begin(); } iterator end() { return Specifiers.end(); } }; } DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) { assert(Start && "Bulding a context chain from a null context"); DeclContextList Chain; for (DeclContext *DC = Start->getPrimaryContext(); DC != NULL; 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; } void NamespaceSpecifierSet::SortNamespaces() { SmallVector sortedDistances; sortedDistances.append(Distances.begin(), Distances.end()); if (sortedDistances.size() > 1) std::sort(sortedDistances.begin(), sortedDistances.end()); Specifiers.clear(); for (SmallVector::iterator DI = sortedDistances.begin(), DIEnd = sortedDistances.end(); DI != DIEnd; ++DI) { SpecifierInfoList &SpecList = DistanceMap[*DI]; Specifiers.append(SpecList.begin(), SpecList.end()); } isSorted = true; } void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) { DeclContext *Ctx = cast(ND); NestedNameSpecifier *NNS = NULL; unsigned NumSpecifiers = 0; DeclContextList NamespaceDeclChain(BuildContextChain(Ctx)); DeclContextList FullNamespaceDeclChain(NamespaceDeclChain); // Eliminate common elements from the two DeclContext chains. for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), CEnd = CurContextChain.rend(); C != CEnd && !NamespaceDeclChain.empty() && NamespaceDeclChain.back() == *C; ++C) { NamespaceDeclChain.pop_back(); } // Add an explicit leading '::' specifier if needed. if (NamespaceDecl *ND = NamespaceDeclChain.empty() ? NULL : dyn_cast_or_null(NamespaceDeclChain.back())) { IdentifierInfo *Name = ND->getIdentifier(); if (std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(), Name) != CurContextIdentifiers.end() || std::find(CurNameSpecifierIdentifiers.begin(), CurNameSpecifierIdentifiers.end(), Name) != CurNameSpecifierIdentifiers.end()) { NamespaceDeclChain = FullNamespaceDeclChain; NNS = NestedNameSpecifier::GlobalSpecifier(Context); } } // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(), CEnd = NamespaceDeclChain.rend(); C != CEnd; ++C) { NamespaceDecl *ND = dyn_cast_or_null(*C); if (ND) { NNS = NestedNameSpecifier::Create(Context, NNS, ND); ++NumSpecifiers; } } // 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::ArrayRef(CurNameSpecifierIdentifiers), llvm::ArrayRef(NewNameSpecifierIdentifiers)); } isSorted = false; Distances.insert(NumSpecifiers); DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers)); } /// \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) { Res.suppressDiagnostics(); Res.clear(); Res.setLookupName(Name); 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)) { 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) { if (CCC.WantObjCSuper) Consumer.addKeywordResult("super"); if (CCC.WantTypeSpecifiers) { // Add type-specifier keywords to the set of results. const char *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 = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]); 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().CPlusPlus0x) { 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"); } 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) { const char *CXXExprs[] = { "delete", "new", "operator", "throw", "typeid" }; const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]); 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().CPlusPlus0x) { Consumer.addKeywordResult("alignof"); Consumer.addKeywordResult("nullptr"); } } } if (CCC.WantRemainingKeywords) { if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) { // Statements. const char *CStmts[] = { "do", "else", "for", "goto", "if", "return", "switch", "while" }; const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]); 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().CPlusPlus0x) Consumer.addKeywordResult("static_assert"); } } } static bool isCandidateViable(CorrectionCandidateCallback &CCC, TypoCorrection &Candidate) { Candidate.setCallbackDistance(CCC.RankCandidate(Candidate)); return Candidate.getEditDistance(false) != TypoCorrection::InvalidDistance; } /// \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, CorrectionCandidateCallback &CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT) { if (Diags.hasFatalErrorOccurred() || !getLangOpts().SpellChecking) return TypoCorrection(); // 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().MicrosoftMode && CurContext->isDependentContext() && isa(CurContext)) return TypoCorrection(); // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!Typo) return TypoCorrection(); // If the scope specifier itself was invalid, don't try to correct // typos. if (SS && SS->isInvalid()) return TypoCorrection(); // Never try to correct typos during template deduction or // instantiation. if (!ActiveTemplateInstantiations.empty()) return TypoCorrection(); NamespaceSpecifierSet Namespaces(Context, CurContext, SS); TypoCorrectionConsumer Consumer(*this, Typo); // If a callback object considers an empty typo correction candidate to be // viable, assume it does not do any actual validation of the candidates. TypoCorrection EmptyCorrection; bool ValidatingCallback = !isCandidateViable(CCC, EmptyCorrection); // 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 (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), E = OPT->qual_end(); I != E; ++I) LookupVisibleDecls(*I, LookupKind, Consumer); } } else if (SS && SS->isSet()) { QualifiedDC = computeDeclContext(*SS, EnteringContext); if (!QualifiedDC) return TypoCorrection(); // 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. if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) return TypoCorrection(); ++TyposCorrected; LookupVisibleDecls(QualifiedDC, LookupKind, Consumer); } else { IsUnqualifiedLookup = true; UnqualifiedTyposCorrectedMap::iterator Cached = UnqualifiedTyposCorrected.find(Typo); if (Cached != UnqualifiedTyposCorrected.end()) { // Add the cached value, unless it's a keyword or fails validation. In the // keyword case, we'll end up adding the keyword below. if (Cached->second) { if (!Cached->second.isKeyword() && isCandidateViable(CCC, Cached->second)) Consumer.addCorrection(Cached->second); } else { // Only honor no-correction cache hits when a callback that will validate // correction candidates is not being used. if (!ValidatingCallback) return TypoCorrection(); } } if (Cached == UnqualifiedTyposCorrected.end()) { // 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. if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) return TypoCorrection(); } } // Determine whether we are going to search in the various namespaces for // corrections. bool SearchNamespaces = getLangOpts().CPlusPlus && (IsUnqualifiedLookup || (QualifiedDC && QualifiedDC->isNamespace())); 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 (IdentifierTable::iterator I = Context.Idents.begin(), IEnd = Context.Idents.end(); I != IEnd; ++I) 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()) { OwningPtr Iter(External->getIdentifiers()); do { StringRef Name = Iter->Next(); if (Name.empty()) break; Consumer.FoundName(Name); } while (true); } } AddKeywordsToConsumer(*this, Consumer, S, CCC); // If we haven't found anything, we're done. if (Consumer.empty()) { // If this was an unqualified lookup, note that no correction was found. if (IsUnqualifiedLookup) (void)UnqualifiedTyposCorrected[Typo]; return TypoCorrection(); } // Make sure that the user typed at least 3 characters for each correction // made. Otherwise, we don't even both looking at the results. unsigned ED = Consumer.getBestEditDistance(true); if (ED > 0 && Typo->getName().size() / ED < 3) { // If this was an unqualified lookup, note that no correction was found. if (IsUnqualifiedLookup) (void)UnqualifiedTyposCorrected[Typo]; return TypoCorrection(); } // 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 (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I) KnownNamespaces[ExternalKnownNamespaces[I]] = true; } for (llvm::DenseMap::iterator KNI = KnownNamespaces.begin(), KNIEnd = KnownNamespaces.end(); KNI != KNIEnd; ++KNI) Namespaces.AddNamespace(KNI->first); } // Weed out any names that could not be found by name lookup or, if a // CorrectionCandidateCallback object was provided, failed validation. llvm::SmallVector QualifiedResults; LookupResult TmpRes(*this, TypoName, LookupKind); TmpRes.suppressDiagnostics(); while (!Consumer.empty()) { TypoCorrectionConsumer::distance_iterator DI = Consumer.begin(); unsigned ED = DI->first; for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(), IEnd = DI->second.end(); I != IEnd; /* Increment in loop. */) { // If the item already has been looked up or is a keyword, keep it. // If a validator callback object was given, drop the correction // unless it passes validation. if (I->second.isResolved()) { TypoCorrectionConsumer::result_iterator Prev = I; ++I; if (!isCandidateViable(CCC, Prev->second)) DI->second.erase(Prev); continue; } // Perform name lookup on this name. IdentifierInfo *Name = I->second.getCorrectionAsIdentifierInfo(); LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext, EnteringContext, CCC.IsObjCIvarLookup); switch (TmpRes.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::FoundUnresolvedValue: QualifiedResults.push_back(I->second); // We didn't find this name in our scope, or didn't like what we found; // ignore it. { TypoCorrectionConsumer::result_iterator Next = I; ++Next; DI->second.erase(I); I = Next; } break; case LookupResult::Ambiguous: // We don't deal with ambiguities. return TypoCorrection(); case LookupResult::FoundOverloaded: { TypoCorrectionConsumer::result_iterator Prev = I; // Store all of the Decls for overloaded symbols for (LookupResult::iterator TRD = TmpRes.begin(), TRDEnd = TmpRes.end(); TRD != TRDEnd; ++TRD) I->second.addCorrectionDecl(*TRD); ++I; if (!isCandidateViable(CCC, Prev->second)) DI->second.erase(Prev); break; } case LookupResult::Found: { TypoCorrectionConsumer::result_iterator Prev = I; I->second.setCorrectionDecl(TmpRes.getAsSingle()); ++I; if (!isCandidateViable(CCC, Prev->second)) DI->second.erase(Prev); break; } } } if (DI->second.empty()) Consumer.erase(DI); else if (!getLangOpts().CPlusPlus || QualifiedResults.empty() || !ED) // If there are results in the closest possible bucket, stop break; // Only perform the qualified lookups for C++ if (SearchNamespaces) { TmpRes.suppressDiagnostics(); for (llvm::SmallVector::iterator QRI = QualifiedResults.begin(), QRIEnd = QualifiedResults.end(); QRI != QRIEnd; ++QRI) { for (NamespaceSpecifierSet::iterator NI = Namespaces.begin(), NIEnd = Namespaces.end(); NI != NIEnd; ++NI) { DeclContext *Ctx = NI->DeclCtx; // FIXME: Stop searching once the namespaces are too far away to create // acceptable corrections for this identifier (since the namespaces // are sorted in ascending order by edit distance). TmpRes.clear(); TmpRes.setLookupName(QRI->getCorrectionAsIdentifierInfo()); if (!LookupQualifiedName(TmpRes, Ctx)) continue; // Any corrections added below will be validated in subsequent // iterations of the main while() loop over the Consumer's contents. switch (TmpRes.getResultKind()) { case LookupResult::Found: { TypoCorrection TC(*QRI); TC.setCorrectionDecl(TmpRes.getAsSingle()); TC.setCorrectionSpecifier(NI->NameSpecifier); TC.setQualifierDistance(NI->EditDistance); Consumer.addCorrection(TC); break; } case LookupResult::FoundOverloaded: { TypoCorrection TC(*QRI); TC.setCorrectionSpecifier(NI->NameSpecifier); TC.setQualifierDistance(NI->EditDistance); for (LookupResult::iterator TRD = TmpRes.begin(), TRDEnd = TmpRes.end(); TRD != TRDEnd; ++TRD) TC.addCorrectionDecl(*TRD); Consumer.addCorrection(TC); break; } case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::Ambiguous: case LookupResult::FoundUnresolvedValue: break; } } } } QualifiedResults.clear(); } // No corrections remain... if (Consumer.empty()) return TypoCorrection(); TypoResultsMap &BestResults = Consumer.begin()->second; ED = TypoCorrection::NormalizeEditDistance(Consumer.begin()->first); if (ED > 0 && Typo->getName().size() / 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. if (IsUnqualifiedLookup && !ValidatingCallback) (void)UnqualifiedTyposCorrected[Typo]; return TypoCorrection(); } // If only a single name remains, return that result. if (BestResults.size() == 1) { const llvm::StringMapEntry &Correction = *(BestResults.begin()); const TypoCorrection &Result = Correction.second; // 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 TypoCorrection(); // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) UnqualifiedTyposCorrected[Typo] = Result; return Result; } else if (BestResults.size() > 1 // 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. && CCC.WantObjCSuper && !CCC.WantRemainingKeywords && BestResults["super"].isKeyword()) { // Prefer 'super' when we're completing in a message-receiver // context. // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. if (ED == 0) return TypoCorrection(); // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) UnqualifiedTyposCorrected[Typo] = BestResults["super"]; return BestResults["super"]; } // If this was an unqualified lookup and we believe the callback object did // not filter out possible corrections, note that no correction was found. if (IsUnqualifiedLookup && !ValidatingCallback) (void)UnqualifiedTyposCorrected[Typo]; return TypoCorrection(); } 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)); CorrectionName.printName(PrefixOStream); return PrefixOStream.str(); } return CorrectionName.getAsString(); } Index: vendor/clang/dist/lib/Sema/SemaType.cpp =================================================================== --- vendor/clang/dist/lib/Sema/SemaType.cpp (revision 235808) +++ vendor/clang/dist/lib/Sema/SemaType.cpp (revision 235809) @@ -1,4513 +1,4514 @@ //===--- SemaType.cpp - Semantic Analysis for Types -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements type-related semantic analysis. // //===----------------------------------------------------------------------===// #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Basic/OpenCL.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/AST/Expr.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Lookup.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; /// isOmittedBlockReturnType - Return true if this declarator is missing a /// return type because this is a omitted return type on a block literal. static bool isOmittedBlockReturnType(const Declarator &D) { if (D.getContext() != Declarator::BlockLiteralContext || D.getDeclSpec().hasTypeSpecifier()) return false; if (D.getNumTypeObjects() == 0) return true; // ^{ ... } if (D.getNumTypeObjects() == 1 && D.getTypeObject(0).Kind == DeclaratorChunk::Function) return true; // ^(int X, float Y) { ... } return false; } /// diagnoseBadTypeAttribute - Diagnoses a type attribute which /// doesn't apply to the given type. static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, QualType type) { bool useExpansionLoc = false; unsigned diagID = 0; switch (attr.getKind()) { case AttributeList::AT_objc_gc: diagID = diag::warn_pointer_attribute_wrong_type; useExpansionLoc = true; break; case AttributeList::AT_objc_ownership: diagID = diag::warn_objc_object_attribute_wrong_type; useExpansionLoc = true; break; default: // Assume everything else was a function attribute. diagID = diag::warn_function_attribute_wrong_type; break; } SourceLocation loc = attr.getLoc(); StringRef name = attr.getName()->getName(); // The GC attributes are usually written with macros; special-case them. if (useExpansionLoc && loc.isMacroID() && attr.getParameterName()) { if (attr.getParameterName()->isStr("strong")) { if (S.findMacroSpelling(loc, "__strong")) name = "__strong"; } else if (attr.getParameterName()->isStr("weak")) { if (S.findMacroSpelling(loc, "__weak")) name = "__weak"; } } S.Diag(loc, diagID) << name << type; } // objc_gc applies to Objective-C pointers or, otherwise, to the // smallest available pointer type (i.e. 'void*' in 'void**'). #define OBJC_POINTER_TYPE_ATTRS_CASELIST \ case AttributeList::AT_objc_gc: \ case AttributeList::AT_objc_ownership // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ case AttributeList::AT_noreturn: \ case AttributeList::AT_cdecl: \ case AttributeList::AT_fastcall: \ case AttributeList::AT_stdcall: \ case AttributeList::AT_thiscall: \ case AttributeList::AT_pascal: \ case AttributeList::AT_regparm: \ case AttributeList::AT_pcs \ namespace { /// An object which stores processing state for the entire /// GetTypeForDeclarator process. class TypeProcessingState { Sema &sema; /// The declarator being processed. Declarator &declarator; /// The index of the declarator chunk we're currently processing. /// May be the total number of valid chunks, indicating the /// DeclSpec. unsigned chunkIndex; /// Whether there are non-trivial modifications to the decl spec. bool trivial; /// Whether we saved the attributes in the decl spec. bool hasSavedAttrs; /// The original set of attributes on the DeclSpec. SmallVector savedAttrs; /// A list of attributes to diagnose the uselessness of when the /// processing is complete. SmallVector ignoredTypeAttrs; public: TypeProcessingState(Sema &sema, Declarator &declarator) : sema(sema), declarator(declarator), chunkIndex(declarator.getNumTypeObjects()), trivial(true), hasSavedAttrs(false) {} Sema &getSema() const { return sema; } Declarator &getDeclarator() const { return declarator; } unsigned getCurrentChunkIndex() const { return chunkIndex; } void setCurrentChunkIndex(unsigned idx) { assert(idx <= declarator.getNumTypeObjects()); chunkIndex = idx; } AttributeList *&getCurrentAttrListRef() const { assert(chunkIndex <= declarator.getNumTypeObjects()); if (chunkIndex == declarator.getNumTypeObjects()) return getMutableDeclSpec().getAttributes().getListRef(); return declarator.getTypeObject(chunkIndex).getAttrListRef(); } /// Save the current set of attributes on the DeclSpec. void saveDeclSpecAttrs() { // Don't try to save them multiple times. if (hasSavedAttrs) return; DeclSpec &spec = getMutableDeclSpec(); for (AttributeList *attr = spec.getAttributes().getList(); attr; attr = attr->getNext()) savedAttrs.push_back(attr); trivial &= savedAttrs.empty(); hasSavedAttrs = true; } /// Record that we had nowhere to put the given type attribute. /// We will diagnose such attributes later. void addIgnoredTypeAttr(AttributeList &attr) { ignoredTypeAttrs.push_back(&attr); } /// Diagnose all the ignored type attributes, given that the /// declarator worked out to the given type. void diagnoseIgnoredTypeAttrs(QualType type) const { for (SmallVectorImpl::const_iterator i = ignoredTypeAttrs.begin(), e = ignoredTypeAttrs.end(); i != e; ++i) diagnoseBadTypeAttribute(getSema(), **i, type); } ~TypeProcessingState() { if (trivial) return; restoreDeclSpecAttrs(); } private: DeclSpec &getMutableDeclSpec() const { return const_cast(declarator.getDeclSpec()); } void restoreDeclSpecAttrs() { assert(hasSavedAttrs); if (savedAttrs.empty()) { getMutableDeclSpec().getAttributes().set(0); return; } getMutableDeclSpec().getAttributes().set(savedAttrs[0]); for (unsigned i = 0, e = savedAttrs.size() - 1; i != e; ++i) savedAttrs[i]->setNext(savedAttrs[i+1]); savedAttrs.back()->setNext(0); } }; /// Basically std::pair except that we really want to avoid an /// implicit operator= for safety concerns. It's also a minor /// link-time optimization for this to be a private type. struct AttrAndList { /// The attribute. AttributeList &first; /// The head of the list the attribute is currently in. AttributeList *&second; AttrAndList(AttributeList &attr, AttributeList *&head) : first(attr), second(head) {} }; } namespace llvm { template <> struct isPodLike { static const bool value = true; }; } static void spliceAttrIntoList(AttributeList &attr, AttributeList *&head) { attr.setNext(head); head = &attr; } static void spliceAttrOutOfList(AttributeList &attr, AttributeList *&head) { if (head == &attr) { head = attr.getNext(); return; } AttributeList *cur = head; while (true) { assert(cur && cur->getNext() && "ran out of attrs?"); if (cur->getNext() == &attr) { cur->setNext(attr.getNext()); return; } cur = cur->getNext(); } } static void moveAttrFromListToList(AttributeList &attr, AttributeList *&fromList, AttributeList *&toList) { spliceAttrOutOfList(attr, fromList); spliceAttrIntoList(attr, toList); } static void processTypeAttrs(TypeProcessingState &state, QualType &type, bool isDeclSpec, AttributeList *attrs); static bool handleFunctionTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type); static bool handleObjCGCTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type); static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type); static bool handleObjCPointerTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type) { if (attr.getKind() == AttributeList::AT_objc_gc) return handleObjCGCTypeAttr(state, attr, type); assert(attr.getKind() == AttributeList::AT_objc_ownership); return handleObjCOwnershipTypeAttr(state, attr, type); } /// Given that an objc_gc attribute was written somewhere on a /// declaration *other* than on the declarator itself (for which, use /// distributeObjCPointerTypeAttrFromDeclarator), and given that it /// didn't apply in whatever position it was written in, try to move /// it to a more appropriate position. static void distributeObjCPointerTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType type) { Declarator &declarator = state.getDeclarator(); for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) { DeclaratorChunk &chunk = declarator.getTypeObject(i-1); switch (chunk.Kind) { case DeclaratorChunk::Pointer: case DeclaratorChunk::BlockPointer: moveAttrFromListToList(attr, state.getCurrentAttrListRef(), chunk.getAttrListRef()); return; case DeclaratorChunk::Paren: case DeclaratorChunk::Array: continue; // Don't walk through these. case DeclaratorChunk::Reference: case DeclaratorChunk::Function: case DeclaratorChunk::MemberPointer: goto error; } } error: diagnoseBadTypeAttribute(state.getSema(), attr, type); } /// Distribute an objc_gc type attribute that was written on the /// declarator. static void distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state, AttributeList &attr, QualType &declSpecType) { Declarator &declarator = state.getDeclarator(); // objc_gc goes on the innermost pointer to something that's not a // pointer. unsigned innermost = -1U; bool considerDeclSpec = true; for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { DeclaratorChunk &chunk = declarator.getTypeObject(i); switch (chunk.Kind) { case DeclaratorChunk::Pointer: case DeclaratorChunk::BlockPointer: innermost = i; continue; case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: case DeclaratorChunk::Paren: case DeclaratorChunk::Array: continue; case DeclaratorChunk::Function: considerDeclSpec = false; goto done; } } done: // That might actually be the decl spec if we weren't blocked by // anything in the declarator. if (considerDeclSpec) { if (handleObjCPointerTypeAttr(state, attr, declSpecType)) { // Splice the attribute into the decl spec. Prevents the // attribute from being applied multiple times and gives // the source-location-filler something to work with. state.saveDeclSpecAttrs(); moveAttrFromListToList(attr, declarator.getAttrListRef(), declarator.getMutableDeclSpec().getAttributes().getListRef()); return; } } // Otherwise, if we found an appropriate chunk, splice the attribute // into it. if (innermost != -1U) { moveAttrFromListToList(attr, declarator.getAttrListRef(), declarator.getTypeObject(innermost).getAttrListRef()); return; } // Otherwise, diagnose when we're done building the type. spliceAttrOutOfList(attr, declarator.getAttrListRef()); state.addIgnoredTypeAttr(attr); } /// A function type attribute was written somewhere in a declaration /// *other* than on the declarator itself or in the decl spec. Given /// that it didn't apply in whatever position it was written in, try /// to move it to a more appropriate position. static void distributeFunctionTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType type) { Declarator &declarator = state.getDeclarator(); // Try to push the attribute from the return type of a function to // the function itself. for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) { DeclaratorChunk &chunk = declarator.getTypeObject(i-1); switch (chunk.Kind) { case DeclaratorChunk::Function: moveAttrFromListToList(attr, state.getCurrentAttrListRef(), chunk.getAttrListRef()); return; case DeclaratorChunk::Paren: case DeclaratorChunk::Pointer: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::Array: case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: continue; } } diagnoseBadTypeAttribute(state.getSema(), attr, type); } /// Try to distribute a function type attribute to the innermost /// function chunk or type. Returns true if the attribute was /// distributed, false if no location was found. static bool distributeFunctionTypeAttrToInnermost(TypeProcessingState &state, AttributeList &attr, AttributeList *&attrList, QualType &declSpecType) { Declarator &declarator = state.getDeclarator(); // Put it on the innermost function chunk, if there is one. for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { DeclaratorChunk &chunk = declarator.getTypeObject(i); if (chunk.Kind != DeclaratorChunk::Function) continue; moveAttrFromListToList(attr, attrList, chunk.getAttrListRef()); return true; } if (handleFunctionTypeAttr(state, attr, declSpecType)) { spliceAttrOutOfList(attr, attrList); return true; } return false; } /// A function type attribute was written in the decl spec. Try to /// apply it somewhere. static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, AttributeList &attr, QualType &declSpecType) { state.saveDeclSpecAttrs(); // Try to distribute to the innermost. if (distributeFunctionTypeAttrToInnermost(state, attr, state.getCurrentAttrListRef(), declSpecType)) return; // If that failed, diagnose the bad attribute when the declarator is // fully built. state.addIgnoredTypeAttr(attr); } /// A function type attribute was written on the declarator. Try to /// apply it somewhere. static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, AttributeList &attr, QualType &declSpecType) { Declarator &declarator = state.getDeclarator(); // Try to distribute to the innermost. if (distributeFunctionTypeAttrToInnermost(state, attr, declarator.getAttrListRef(), declSpecType)) return; // If that failed, diagnose the bad attribute when the declarator is // fully built. spliceAttrOutOfList(attr, declarator.getAttrListRef()); state.addIgnoredTypeAttr(attr); } /// \brief Given that there are attributes written on the declarator /// itself, try to distribute any type attributes to the appropriate /// declarator chunk. /// /// These are attributes like the following: /// int f ATTR; /// int (f ATTR)(); /// but not necessarily this: /// int f() ATTR; static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, QualType &declSpecType) { // Collect all the type attributes from the declarator itself. assert(state.getDeclarator().getAttributes() && "declarator has no attrs!"); AttributeList *attr = state.getDeclarator().getAttributes(); AttributeList *next; do { next = attr->getNext(); switch (attr->getKind()) { OBJC_POINTER_TYPE_ATTRS_CASELIST: distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType); break; case AttributeList::AT_ns_returns_retained: if (!state.getSema().getLangOpts().ObjCAutoRefCount) break; // fallthrough FUNCTION_TYPE_ATTRS_CASELIST: distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType); break; default: break; } } while ((attr = next)); } /// Add a synthetic '()' to a block-literal declarator if it is /// required, given the return type. static void maybeSynthesizeBlockSignature(TypeProcessingState &state, QualType declSpecType) { Declarator &declarator = state.getDeclarator(); // First, check whether the declarator would produce a function, // i.e. whether the innermost semantic chunk is a function. if (declarator.isFunctionDeclarator()) { // If so, make that declarator a prototyped declarator. declarator.getFunctionTypeInfo().hasPrototype = true; return; } // If there are any type objects, the type as written won't name a // function, regardless of the decl spec type. This is because a // block signature declarator is always an abstract-declarator, and // abstract-declarators can't just be parentheses chunks. Therefore // we need to build a function chunk unless there are no type // objects and the decl spec type is a function. if (!declarator.getNumTypeObjects() && declSpecType->isFunctionType()) return; // Note that there *are* cases with invalid declarators where // declarators consist solely of parentheses. In general, these // occur only in failed efforts to make function declarators, so // faking up the function chunk is still the right thing to do. // Otherwise, we need to fake up a function declarator. SourceLocation loc = declarator.getLocStart(); // ...and *prepend* it to the declarator. declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction( /*proto*/ true, /*variadic*/ false, SourceLocation(), /*args*/ 0, 0, /*type quals*/ 0, /*ref-qualifier*/true, SourceLocation(), /*const qualifier*/SourceLocation(), /*volatile qualifier*/SourceLocation(), /*mutable qualifier*/SourceLocation(), - /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, 0, + /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, /*parens*/ loc, loc, declarator)); // For consistency, make sure the state still has us as processing // the decl spec. assert(state.getCurrentChunkIndex() == declarator.getNumTypeObjects() - 1); state.setCurrentChunkIndex(declarator.getNumTypeObjects()); } /// \brief Convert the specified declspec to the appropriate type /// object. /// \param D the declarator containing the declaration specifier. /// \returns The type described by the declaration specifiers. This function /// never returns null. static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. Sema &S = state.getSema(); Declarator &declarator = state.getDeclarator(); const DeclSpec &DS = declarator.getDeclSpec(); SourceLocation DeclLoc = declarator.getIdentifierLoc(); if (DeclLoc.isInvalid()) DeclLoc = DS.getLocStart(); ASTContext &Context = S.Context; QualType Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_void: Result = Context.VoidTy; break; case DeclSpec::TST_char: if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.CharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) Result = Context.SignedCharTy; else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); Result = Context.UnsignedCharTy; } break; case DeclSpec::TST_wchar: if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.WCharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getSignedWCharType(); } else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getUnsignedWCharType(); } break; case DeclSpec::TST_char16: assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && "Unknown TSS value"); Result = Context.Char16Ty; break; case DeclSpec::TST_char32: assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && "Unknown TSS value"); Result = Context.Char32Ty; break; case DeclSpec::TST_unspecified: // "" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Result); break; } // If this is a missing declspec in a block literal return context, then it // is inferred from the return statements inside the block. // The declspec is always missing in a lambda expr context; it is either // specified with a trailing return type or inferred. if (declarator.getContext() == Declarator::LambdaExprContext || isOmittedBlockReturnType(declarator)) { Result = Context.DependentTy; break; } // Unspecified typespec defaults to int in C90. However, the C90 grammar // [C90 6.5] only allows a decl-spec if there was *some* type-specifier, // type-qualifier, or storage-class-specifier. If not, emit an extwarn. // Note that the one exception to this is function definitions, which are // allowed to be completely missing a declspec. This is handled in the // parser already though by it pretending to have seen an 'int' in this // case. if (S.getLangOpts().ImplicitInt) { // In C89 mode, we only warn if there is a completely missing declspec // when one is not allowed. if (DS.isEmpty()) { S.Diag(DeclLoc, diag::ext_missing_declspec) << DS.getSourceRange() << FixItHint::CreateInsertion(DS.getLocStart(), "int"); } } else if (!DS.hasTypeSpecifier()) { // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says: // "At least one type specifier shall be given in the declaration // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." // FIXME: Does Microsoft really have the implicit int extension in C++? if (S.getLangOpts().CPlusPlus && !S.getLangOpts().MicrosoftExt) { S.Diag(DeclLoc, diag::err_missing_type_specifier) << DS.getSourceRange(); // When this occurs in C++ code, often something is very broken with the // value being declared, poison it as invalid so we don't get chains of // errors. declarator.setInvalidType(true); } else { S.Diag(DeclLoc, diag::ext_missing_type_specifier) << DS.getSourceRange(); } } // FALL THROUGH. case DeclSpec::TST_int: { if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { switch (DS.getTypeSpecWidth()) { case DeclSpec::TSW_unspecified: Result = Context.IntTy; break; case DeclSpec::TSW_short: Result = Context.ShortTy; break; case DeclSpec::TSW_long: Result = Context.LongTy; break; case DeclSpec::TSW_longlong: Result = Context.LongLongTy; // long long is a C99 feature. if (!S.getLangOpts().C99) S.Diag(DS.getTypeSpecWidthLoc(), S.getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_longlong : diag::ext_longlong); break; } } else { switch (DS.getTypeSpecWidth()) { case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break; case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break; case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break; case DeclSpec::TSW_longlong: Result = Context.UnsignedLongLongTy; // long long is a C99 feature. if (!S.getLangOpts().C99) S.Diag(DS.getTypeSpecWidthLoc(), S.getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_longlong : diag::ext_longlong); break; } } break; } case DeclSpec::TST_int128: if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) Result = Context.UnsignedInt128Ty; else Result = Context.Int128Ty; break; case DeclSpec::TST_half: Result = Context.HalfTy; break; case DeclSpec::TST_float: Result = Context.FloatTy; break; case DeclSpec::TST_double: if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) Result = Context.LongDoubleTy; else Result = Context.DoubleTy; if (S.getLangOpts().OpenCL && !S.getOpenCLOptions().cl_khr_fp64) { S.Diag(DS.getTypeSpecTypeLoc(), diag::err_double_requires_fp64); declarator.setInvalidType(true); } break; case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool case DeclSpec::TST_decimal32: // _Decimal32 case DeclSpec::TST_decimal64: // _Decimal64 case DeclSpec::TST_decimal128: // _Decimal128 S.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); Result = Context.IntTy; declarator.setInvalidType(true); break; case DeclSpec::TST_class: case DeclSpec::TST_enum: case DeclSpec::TST_union: case DeclSpec::TST_struct: { TypeDecl *D = dyn_cast_or_null(DS.getRepAsDecl()); if (!D) { // This can happen in C++ with ambiguous lookups. Result = Context.IntTy; declarator.setInvalidType(true); break; } // If the type is deprecated or unavailable, diagnose it. S.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeNameLoc()); assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!"); // TypeQuals handled by caller. Result = Context.getTypeDeclType(D); // In both C and C++, make an ElaboratedType. ElaboratedTypeKeyword Keyword = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result); break; } case DeclSpec::TST_typename: { assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); Result = S.GetTypeFromParser(DS.getRepAsType()); if (Result.isNull()) declarator.setInvalidType(true); else if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { if (const ObjCObjectType *ObjT = Result->getAs()) { // Silently drop any existing protocol qualifiers. // TODO: determine whether that's the right thing to do. if (ObjT->getNumProtocols()) Result = ObjT->getBaseType(); if (DS.getNumProtocolQualifiers()) Result = Context.getObjCObjectType(Result, (ObjCProtocolDecl**) PQ, DS.getNumProtocolQualifiers()); } else if (Result->isObjCIdType()) { // id Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, (ObjCProtocolDecl**) PQ, DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Result); } else if (Result->isObjCClassType()) { // Class Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, (ObjCProtocolDecl**) PQ, DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Result); } else { S.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); declarator.setInvalidType(true); } } // TypeQuals handled by caller. break; } case DeclSpec::TST_typeofType: // FIXME: Preserve type source info. Result = S.GetTypeFromParser(DS.getRepAsType()); assert(!Result.isNull() && "Didn't get a type for typeof?"); if (!Result->isDependentType()) if (const TagType *TT = Result->getAs()) S.DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc()); // TypeQuals handled by caller. Result = Context.getTypeOfType(Result); break; case DeclSpec::TST_typeofExpr: { Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); } break; } case DeclSpec::TST_decltype: { Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); } break; } case DeclSpec::TST_underlyingType: Result = S.GetTypeFromParser(DS.getRepAsType()); assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); Result = S.BuildUnaryTransformType(Result, UnaryTransformType::EnumUnderlyingType, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); } break; case DeclSpec::TST_auto: { // TypeQuals handled by caller. Result = Context.getAutoType(QualType()); break; } case DeclSpec::TST_unknown_anytype: Result = Context.UnknownAnyTy; break; case DeclSpec::TST_atomic: Result = S.GetTypeFromParser(DS.getRepAsType()); assert(!Result.isNull() && "Didn't get a type for _Atomic?"); Result = S.BuildAtomicType(Result, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); } break; case DeclSpec::TST_error: Result = Context.IntTy; declarator.setInvalidType(true); break; } // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { if (S.getLangOpts().Freestanding) S.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); Result = Context.getComplexType(Result); } else if (DS.isTypeAltiVecVector()) { unsigned typeSize = static_cast(Context.getTypeSize(Result)); assert(typeSize > 0 && "type size for vector must be greater than 0 bits"); VectorType::VectorKind VecKind = VectorType::AltiVecVector; if (DS.isTypeAltiVecPixel()) VecKind = VectorType::AltiVecPixel; else if (DS.isTypeAltiVecBool()) VecKind = VectorType::AltiVecBool; Result = Context.getVectorType(Result, 128/typeSize, VecKind); } // FIXME: Imaginary. if (DS.getTypeSpecComplex() == DeclSpec::TSC_imaginary) S.Diag(DS.getTypeSpecComplexLoc(), diag::err_imaginary_not_supported); // Before we process any type attributes, synthesize a block literal // function declarator if necessary. if (declarator.getContext() == Declarator::BlockLiteralContext) maybeSynthesizeBlockSignature(state, Result); // Apply any type attributes from the decl spec. This may cause the // list of type attributes to be temporarily saved while the type // attributes are pushed around. if (AttributeList *attrs = DS.getAttributes().getList()) processTypeAttrs(state, Result, true, attrs); // Apply const/volatile/restrict qualifiers to T. 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." C++ also allows // restrict-qualified references. if (TypeQuals & DeclSpec::TQ_restrict) { if (Result->isAnyPointerType() || Result->isReferenceType()) { QualType EltTy; if (Result->isObjCObjectPointerType()) EltTy = Result; else EltTy = Result->isPointerType() ? Result->getAs()->getPointeeType() : Result->getAs()->getPointeeType(); // If we have a pointer or reference, the pointee must have an object // incomplete type. if (!EltTy->isIncompleteOrObjectType()) { S.Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_invalid_pointee) << EltTy << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } else { S.Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_not_pointer) << Result << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } // Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification // of a function type includes any type qualifiers, the behavior is // undefined." if (Result->isFunctionType() && TypeQuals) { // Get some location to point at, either the C or V location. SourceLocation Loc; if (TypeQuals & DeclSpec::TQ_const) Loc = DS.getConstSpecLoc(); else if (TypeQuals & DeclSpec::TQ_volatile) Loc = DS.getVolatileSpecLoc(); else { assert((TypeQuals & DeclSpec::TQ_restrict) && "Has CVR quals but not C, V, or R?"); Loc = DS.getRestrictSpecLoc(); } S.Diag(Loc, diag::warn_typecheck_function_qualifiers) << Result << DS.getSourceRange(); } // C++ [dcl.ref]p1: // Cv-qualified references are ill-formed except when the // cv-qualifiers are introduced through the use of a typedef // (7.1.3) or of a template type argument (14.3), in which // case the cv-qualifiers are ignored. // FIXME: Shouldn't we be checking SCS_typedef here? if (DS.getTypeSpecType() == DeclSpec::TST_typename && TypeQuals && Result->isReferenceType()) { TypeQuals &= ~DeclSpec::TQ_const; TypeQuals &= ~DeclSpec::TQ_volatile; } // C90 6.5.3 constraints: "The same type qualifier shall not appear more // than once in the same specifier-list or qualifier-list, either directly // or via one or more typedefs." if (!S.getLangOpts().C99 && !S.getLangOpts().CPlusPlus && TypeQuals & Result.getCVRQualifiers()) { if (TypeQuals & DeclSpec::TQ_const && Result.isConstQualified()) { S.Diag(DS.getConstSpecLoc(), diag::ext_duplicate_declspec) << "const"; } if (TypeQuals & DeclSpec::TQ_volatile && Result.isVolatileQualified()) { S.Diag(DS.getVolatileSpecLoc(), diag::ext_duplicate_declspec) << "volatile"; } // C90 doesn't have restrict, so it doesn't force us to produce a warning // in this case. } Qualifiers Quals = Qualifiers::fromCVRMask(TypeQuals); Result = Context.getQualifiedType(Result, Quals); } return Result; } static std::string getPrintableNameForEntity(DeclarationName Entity) { if (Entity) return Entity.getAsString(); return "type name"; } QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs) { // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." if (Qs.hasRestrict()) { unsigned DiagID = 0; QualType ProblemTy; const Type *Ty = T->getCanonicalTypeInternal().getTypePtr(); if (const ReferenceType *RTy = dyn_cast(Ty)) { if (!RTy->getPointeeType()->isIncompleteOrObjectType()) { DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; ProblemTy = T->getAs()->getPointeeType(); } } else if (const PointerType *PTy = dyn_cast(Ty)) { if (!PTy->getPointeeType()->isIncompleteOrObjectType()) { DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; ProblemTy = T->getAs()->getPointeeType(); } } else if (const MemberPointerType *PTy = dyn_cast(Ty)) { if (!PTy->getPointeeType()->isIncompleteOrObjectType()) { DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; ProblemTy = T->getAs()->getPointeeType(); } } else if (!Ty->isDependentType()) { // FIXME: this deserves a proper diagnostic DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; ProblemTy = T; } if (DiagID) { Diag(Loc, DiagID) << ProblemTy; Qs.removeRestrict(); } } return Context.getQualifiedType(T, Qs); } /// \brief Build a paren type including \p T. QualType Sema::BuildParenType(QualType T) { return Context.getParenType(T); } /// Given that we're building a pointer or reference to the given static QualType inferARCLifetimeForPointee(Sema &S, QualType type, SourceLocation loc, bool isReference) { // Bail out if retention is unrequired or already specified. if (!type->isObjCLifetimeType() || type.getObjCLifetime() != Qualifiers::OCL_None) return type; Qualifiers::ObjCLifetime implicitLifetime = Qualifiers::OCL_None; // If the object type is const-qualified, we can safely use // __unsafe_unretained. This is safe (because there are no read // barriers), and it'll be safe to coerce anything but __weak* to // the resulting type. if (type.isConstQualified()) { implicitLifetime = Qualifiers::OCL_ExplicitNone; // Otherwise, check whether the static type does not require // retaining. This currently only triggers for Class (possibly // protocol-qualifed, and arrays thereof). } else if (type->isObjCARCImplicitlyUnretainedType()) { implicitLifetime = Qualifiers::OCL_ExplicitNone; // If we are in an unevaluated context, like sizeof, skip adding a // qualification. } else if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) { return type; // If that failed, give an error and recover using __strong. __strong // is the option most likely to prevent spurious second-order diagnostics, // like when binding a reference to a field. } else { // These types can show up in private ivars in system headers, so // we need this to not be an error in those cases. Instead we // want to delay. if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { S.DelayedDiagnostics.add( sema::DelayedDiagnostic::makeForbiddenType(loc, diag::err_arc_indirect_no_ownership, type, isReference)); } else { S.Diag(loc, diag::err_arc_indirect_no_ownership) << type << isReference; } implicitLifetime = Qualifiers::OCL_Strong; } assert(implicitLifetime && "didn't infer any lifetime!"); Qualifiers qs; qs.addObjCLifetime(implicitLifetime); return S.Context.getQualifiedType(type, qs); } /// \brief Build a pointer type. /// /// \param T The type to which we'll be building a pointer. /// /// \param Loc The location of the entity whose type involves this /// pointer type or, if there is no such entity, the location of the /// type that will have pointer type. /// /// \param Entity The name of the entity that involves the pointer /// type, if known. /// /// \returns A suitable pointer type, if there are no /// errors. Otherwise, returns a NULL type. QualType Sema::BuildPointerType(QualType T, SourceLocation Loc, DeclarationName Entity) { if (T->isReferenceType()) { // C++ 8.3.2p4: There shall be no ... pointers to references ... Diag(Loc, diag::err_illegal_decl_pointer_to_reference) << getPrintableNameForEntity(Entity) << T; return QualType(); } assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); // In ARC, it is forbidden to build pointers to unqualified pointers. if (getLangOpts().ObjCAutoRefCount) T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false); // Build the pointer type. return Context.getPointerType(T); } /// \brief Build a reference type. /// /// \param T The type to which we'll be building a reference. /// /// \param Loc The location of the entity whose type involves this /// reference type or, if there is no such entity, the location of the /// type that will have reference type. /// /// \param Entity The name of the entity that involves the reference /// type, if known. /// /// \returns A suitable reference type, if there are no /// errors. Otherwise, returns a NULL type. QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, SourceLocation Loc, DeclarationName Entity) { assert(Context.getCanonicalType(T) != Context.OverloadTy && "Unresolved overloaded function type"); // C++0x [dcl.ref]p6: // If a typedef (7.1.3), a type template-parameter (14.3.1), or a // decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a // type T, an attempt to create the type "lvalue reference to cv TR" creates // the type "lvalue reference to T", while an attempt to create the type // "rvalue reference to cv TR" creates the type TR. bool LValueRef = SpelledAsLValue || T->getAs(); // C++ [dcl.ref]p4: There shall be no references to references. // // According to C++ DR 106, references to references are only // diagnosed when they are written directly (e.g., "int & &"), // but not when they happen via a typedef: // // typedef int& intref; // typedef intref& intref2; // // Parser::ParseDeclaratorInternal diagnoses the case where // references are written directly; here, we handle the // collapsing of references-to-references as described in C++0x. // DR 106 and 540 introduce reference-collapsing into C++98/03. // C++ [dcl.ref]p1: // A declarator that specifies the type "reference to cv void" // is ill-formed. if (T->isVoidType()) { Diag(Loc, diag::err_reference_to_void); return QualType(); } // In ARC, it is forbidden to build references to unqualified pointers. if (getLangOpts().ObjCAutoRefCount) T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true); // Handle restrict on references. if (LValueRef) return Context.getLValueReferenceType(T, SpelledAsLValue); return Context.getRValueReferenceType(T); } /// Check whether the specified array size makes the array type a VLA. If so, /// return true, if not, return the size of the array in SizeVal. static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) { // If the size is an ICE, it certainly isn't a VLA. If we're in a GNU mode // (like gnu99, but not c99) accept any evaluatable value as an extension. return S.VerifyIntegerConstantExpression( ArraySize, &SizeVal, S.PDiag(), S.LangOpts.GNUMode, S.PDiag(diag::ext_vla_folded_to_constant)).isInvalid(); } /// \brief Build an array type. /// /// \param T The type of each element in the array. /// /// \param ASM C99 array size modifier (e.g., '*', 'static'). /// /// \param ArraySize Expression describing the size of the array. /// /// \param Loc The location of the entity whose type involves this /// array type or, if there is no such entity, the location of the /// type that will have array type. /// /// \param Entity The name of the entity that involves the array /// type, if known. /// /// \returns A suitable array type, if there are no errors. Otherwise, /// returns a NULL type. QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, SourceRange Brackets, DeclarationName Entity) { SourceLocation Loc = Brackets.getBegin(); if (getLangOpts().CPlusPlus) { // C++ [dcl.array]p1: // T is called the array element type; this type shall not be a reference // type, the (possibly cv-qualified) type void, a function type or an // abstract class type. // // Note: function types are handled in the common path with C. if (T->isReferenceType()) { Diag(Loc, diag::err_illegal_decl_array_of_references) << getPrintableNameForEntity(Entity) << T; return QualType(); } if (T->isVoidType()) { Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T; return QualType(); } if (RequireNonAbstractType(Brackets.getBegin(), T, diag::err_array_of_abstract_type)) return QualType(); } else { // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) if (RequireCompleteType(Loc, T, diag::err_illegal_decl_array_incomplete_type)) return QualType(); } if (T->isFunctionType()) { Diag(Loc, diag::err_illegal_decl_array_of_functions) << getPrintableNameForEntity(Entity) << T; return QualType(); } if (T->getContainedAutoType()) { Diag(Loc, diag::err_illegal_decl_array_of_auto) << getPrintableNameForEntity(Entity) << T; return QualType(); } if (const RecordType *EltTy = T->getAs()) { // If the element type is a struct or union that contains a variadic // array, accept it as a GNU extension: C99 6.7.2.1p2. if (EltTy->getDecl()->hasFlexibleArrayMember()) Diag(Loc, diag::ext_flexible_array_in_array) << T; } else if (T->isObjCObjectType()) { Diag(Loc, diag::err_objc_array_of_interfaces) << T; return QualType(); } // Do placeholder conversions on the array size expression. if (ArraySize && ArraySize->hasPlaceholderType()) { ExprResult Result = CheckPlaceholderExpr(ArraySize); if (Result.isInvalid()) return QualType(); ArraySize = Result.take(); } // Do lvalue-to-rvalue conversions on the array size expression. if (ArraySize && !ArraySize->isRValue()) { ExprResult Result = DefaultLvalueConversion(ArraySize); if (Result.isInvalid()) return QualType(); ArraySize = Result.take(); } // C99 6.7.5.2p1: The size expression shall have integer type. // C++11 allows contextual conversions to such types. if (!getLangOpts().CPlusPlus0x && ArraySize && !ArraySize->isTypeDependent() && !ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) { Diag(ArraySize->getLocStart(), diag::err_array_size_non_int) << ArraySize->getType() << ArraySize->getSourceRange(); return QualType(); } llvm::APSInt ConstVal(Context.getTypeSize(Context.getSizeType())); if (!ArraySize) { if (ASM == ArrayType::Star) T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets); else T = Context.getIncompleteArrayType(T, ASM, Quals); } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); } else if ((!T->isDependentType() && !T->isIncompleteType() && !T->isConstantSizeType()) || isArraySizeVLA(*this, ArraySize, ConstVal)) { // Even in C++11, don't allow contextual conversions in the array bound // of a VLA. if (getLangOpts().CPlusPlus0x && !ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) { Diag(ArraySize->getLocStart(), diag::err_array_size_non_int) << ArraySize->getType() << ArraySize->getSourceRange(); return QualType(); } // C99: an array with an element type that has a non-constant-size is a VLA. // C99: an array with a non-ICE size is a VLA. We accept any expression // that we can fold to a non-zero positive value as an extension. T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall // have a value greater than zero. if (ConstVal.isSigned() && ConstVal.isNegative()) { if (Entity) Diag(ArraySize->getLocStart(), diag::err_decl_negative_array_size) << getPrintableNameForEntity(Entity) << ArraySize->getSourceRange(); else Diag(ArraySize->getLocStart(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange(); return QualType(); } if (ConstVal == 0) { // GCC accepts zero sized static arrays. We allow them when // we're not in a SFINAE context. Diag(ArraySize->getLocStart(), isSFINAEContext()? diag::err_typecheck_zero_array_size : diag::ext_typecheck_zero_array_size) << ArraySize->getSourceRange(); if (ASM == ArrayType::Static) { Diag(ArraySize->getLocStart(), diag::warn_typecheck_zero_static_array_size) << ArraySize->getSourceRange(); ASM = ArrayType::Normal; } } else if (!T->isDependentType() && !T->isVariablyModifiedType() && !T->isIncompleteType()) { // Is the array too large? unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, T, ConstVal); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) Diag(ArraySize->getLocStart(), diag::err_array_too_large) << ConstVal.toString(10) << ArraySize->getSourceRange(); } T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); } // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOpts().C99) { if (T->isVariableArrayType()) { // Prohibit the use of non-POD types in VLAs. QualType BaseT = Context.getBaseElementType(T); if (!T->isDependentType() && !BaseT.isPODType(Context) && !BaseT->isObjCLifetimeType()) { Diag(Loc, diag::err_vla_non_pod) << BaseT; return QualType(); } // Prohibit the use of VLAs during template argument deduction. else if (isSFINAEContext()) { Diag(Loc, diag::err_vla_in_sfinae); return QualType(); } // Just extwarn about VLAs. else Diag(Loc, diag::ext_vla); } else if (ASM != ArrayType::Normal || Quals != 0) Diag(Loc, getLangOpts().CPlusPlus? diag::err_c99_array_usage_cxx : diag::ext_c99_array_usage) << ASM; } return T; } /// \brief Build an ext-vector type. /// /// Run the required checks for the extended vector type. QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc) { // unlike gcc's vector_size attribute, we do not allow vectors to be defined // in conjunction with complex types (pointers, arrays, functions, etc.). if (!T->isDependentType() && !T->isIntegerType() && !T->isRealFloatingType()) { Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T; return QualType(); } if (!ArraySize->isTypeDependent() && !ArraySize->isValueDependent()) { llvm::APSInt vecSize(32); if (!ArraySize->isIntegerConstantExpr(vecSize, Context)) { Diag(AttrLoc, diag::err_attribute_argument_not_int) << "ext_vector_type" << ArraySize->getSourceRange(); return QualType(); } // unlike gcc's vector_size attribute, the size is specified as the // number of elements, not the number of bytes. unsigned vectorSize = static_cast(vecSize.getZExtValue()); if (vectorSize == 0) { Diag(AttrLoc, diag::err_attribute_zero_size) << ArraySize->getSourceRange(); return QualType(); } return Context.getExtVectorType(T, vectorSize); } return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc); } /// \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 NumParamTypes The number of parameter types in ParamTypes. /// /// \param Variadic Whether this is a variadic function type. /// /// \param HasTrailingReturn Whether this function has a trailing return type. /// /// \param Quals The cvr-qualifiers to be applied to the function type. /// /// \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. /// /// \returns A suitable function type, if there are no /// errors. Otherwise, returns a NULL type. QualType Sema::BuildFunctionType(QualType T, QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, bool HasTrailingReturn, unsigned Quals, RefQualifierKind RefQualifier, SourceLocation Loc, DeclarationName Entity, FunctionType::ExtInfo Info) { if (T->isArrayType() || T->isFunctionType()) { Diag(Loc, diag::err_func_returning_array_function) << T->isFunctionType() << T; return QualType(); } // Functions cannot return half FP. if (T->isHalfType()) { Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 << FixItHint::CreateInsertion(Loc, "*"); return QualType(); } bool Invalid = false; for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) { // FIXME: Loc is too inprecise here, should use proper locations for args. QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]); if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; } else if (ParamType->isHalfType()) { // Disallow half FP arguments. Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 << FixItHint::CreateInsertion(Loc, "*"); Invalid = true; } ParamTypes[Idx] = ParamType; } if (Invalid) return QualType(); FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = Variadic; EPI.HasTrailingReturn = HasTrailingReturn; EPI.TypeQuals = Quals; EPI.RefQualifier = RefQualifier; EPI.ExtInfo = Info; return Context.getFunctionType(T, ParamTypes, NumParamTypes, EPI); } /// \brief Build a member pointer type \c T Class::*. /// /// \param T the type to which the member pointer refers. /// \param Class the class type into which the member pointer points. /// \param Loc the location where this type begins /// \param Entity the name of the entity that will have this member pointer type /// /// \returns a member pointer type, if successful, or a NULL type if there was /// an error. QualType Sema::BuildMemberPointerType(QualType T, QualType Class, SourceLocation Loc, DeclarationName Entity) { // Verify that we're not building a pointer to pointer to function with // exception specification. if (CheckDistantExceptionSpec(T)) { Diag(Loc, diag::err_distant_exception_spec); // FIXME: If we're doing this as part of template instantiation, // we should return immediately. // Build the type anyway, but use the canonical type so that the // exception specifiers are stripped off. T = Context.getCanonicalType(T); } // C++ 8.3.3p3: A pointer to member shall not point to ... a member // with reference type, or "cv void." if (T->isReferenceType()) { Diag(Loc, diag::err_illegal_decl_mempointer_to_reference) << (Entity? Entity.getAsString() : "type name") << T; return QualType(); } if (T->isVoidType()) { Diag(Loc, diag::err_illegal_decl_mempointer_to_void) << (Entity? Entity.getAsString() : "type name"); return QualType(); } if (!Class->isDependentType() && !Class->isRecordType()) { Diag(Loc, diag::err_mempointer_in_nonclass_type) << Class; return QualType(); } // In the Microsoft ABI, the class is allowed to be an incomplete // type. In such cases, the compiler makes a worst-case assumption. // We make no such assumption right now, so emit an error if the // class isn't a complete type. if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft && RequireCompleteType(Loc, Class, diag::err_incomplete_type)) return QualType(); return Context.getMemberPointerType(T, Class.getTypePtr()); } /// \brief Build a block pointer type. /// /// \param T The type to which we'll be building a block pointer. /// /// \param CVR The cvr-qualifiers to be applied to the block pointer type. /// /// \param Loc The location of the entity whose type involves this /// block pointer type or, if there is no such entity, the location of the /// type that will have block pointer type. /// /// \param Entity The name of the entity that involves the block pointer /// type, if known. /// /// \returns A suitable block pointer type, if there are no /// errors. Otherwise, returns a NULL type. QualType Sema::BuildBlockPointerType(QualType T, SourceLocation Loc, DeclarationName Entity) { if (!T->isFunctionType()) { Diag(Loc, diag::err_nonfunction_block_type); return QualType(); } return Context.getBlockPointerType(T); } QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) { QualType QT = Ty.get(); if (QT.isNull()) { if (TInfo) *TInfo = 0; return QualType(); } TypeSourceInfo *DI = 0; if (const LocInfoType *LIT = dyn_cast(QT)) { QT = LIT->getType(); DI = LIT->getTypeSourceInfo(); } if (TInfo) *TInfo = DI; return QT; } static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, Qualifiers::ObjCLifetime ownership, unsigned chunkIndex); /// Given that this is the declaration of a parameter under ARC, /// attempt to infer attributes and such for pointer-to-whatever /// types. static void inferARCWriteback(TypeProcessingState &state, QualType &declSpecType) { Sema &S = state.getSema(); Declarator &declarator = state.getDeclarator(); // TODO: should we care about decl qualifiers? // Check whether the declarator has the expected form. We walk // from the inside out in order to make the block logic work. unsigned outermostPointerIndex = 0; bool isBlockPointer = false; unsigned numPointers = 0; for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { unsigned chunkIndex = i; DeclaratorChunk &chunk = declarator.getTypeObject(chunkIndex); switch (chunk.Kind) { case DeclaratorChunk::Paren: // Ignore parens. break; case DeclaratorChunk::Reference: case DeclaratorChunk::Pointer: // Count the number of pointers. Treat references // interchangeably as pointers; if they're mis-ordered, normal // type building will discover that. outermostPointerIndex = chunkIndex; numPointers++; break; case DeclaratorChunk::BlockPointer: // If we have a pointer to block pointer, that's an acceptable // indirect reference; anything else is not an application of // the rules. if (numPointers != 1) return; numPointers++; outermostPointerIndex = chunkIndex; isBlockPointer = true; // We don't care about pointer structure in return values here. goto done; case DeclaratorChunk::Array: // suppress if written (id[])? case DeclaratorChunk::Function: case DeclaratorChunk::MemberPointer: return; } } done: // If we have *one* pointer, then we want to throw the qualifier on // the declaration-specifiers, which means that it needs to be a // retainable object type. if (numPointers == 1) { // If it's not a retainable object type, the rule doesn't apply. if (!declSpecType->isObjCRetainableType()) return; // If it already has lifetime, don't do anything. if (declSpecType.getObjCLifetime()) return; // Otherwise, modify the type in-place. Qualifiers qs; if (declSpecType->isObjCARCImplicitlyUnretainedType()) qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone); else qs.addObjCLifetime(Qualifiers::OCL_Autoreleasing); declSpecType = S.Context.getQualifiedType(declSpecType, qs); // If we have *two* pointers, then we want to throw the qualifier on // the outermost pointer. } else if (numPointers == 2) { // If we don't have a block pointer, we need to check whether the // declaration-specifiers gave us something that will turn into a // retainable object pointer after we slap the first pointer on it. if (!isBlockPointer && !declSpecType->isObjCObjectType()) return; // Look for an explicit lifetime attribute there. DeclaratorChunk &chunk = declarator.getTypeObject(outermostPointerIndex); if (chunk.Kind != DeclaratorChunk::Pointer && chunk.Kind != DeclaratorChunk::BlockPointer) return; for (const AttributeList *attr = chunk.getAttrs(); attr; attr = attr->getNext()) if (attr->getKind() == AttributeList::AT_objc_ownership) return; transferARCOwnershipToDeclaratorChunk(state, Qualifiers::OCL_Autoreleasing, outermostPointerIndex); // Any other number of pointers/references does not trigger the rule. } else return; // TODO: mark whether we did this inference? } static void DiagnoseIgnoredQualifiers(unsigned Quals, SourceLocation ConstQualLoc, SourceLocation VolatileQualLoc, SourceLocation RestrictQualLoc, Sema& S) { std::string QualStr; unsigned NumQuals = 0; SourceLocation Loc; FixItHint ConstFixIt; FixItHint VolatileFixIt; FixItHint RestrictFixIt; const SourceManager &SM = S.getSourceManager(); // FIXME: The locations here are set kind of arbitrarily. It'd be nicer to // find a range and grow it to encompass all the qualifiers, regardless of // the order in which they textually appear. if (Quals & Qualifiers::Const) { ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc); QualStr = "const"; ++NumQuals; if (!Loc.isValid() || SM.isBeforeInTranslationUnit(ConstQualLoc, Loc)) Loc = ConstQualLoc; } if (Quals & Qualifiers::Volatile) { VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc); QualStr += (NumQuals == 0 ? "volatile" : " volatile"); ++NumQuals; if (!Loc.isValid() || SM.isBeforeInTranslationUnit(VolatileQualLoc, Loc)) Loc = VolatileQualLoc; } if (Quals & Qualifiers::Restrict) { RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc); QualStr += (NumQuals == 0 ? "restrict" : " restrict"); ++NumQuals; if (!Loc.isValid() || SM.isBeforeInTranslationUnit(RestrictQualLoc, Loc)) Loc = RestrictQualLoc; } assert(NumQuals > 0 && "No known qualifiers?"); S.Diag(Loc, diag::warn_qual_return_type) << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt; } static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, TypeSourceInfo *&ReturnTypeInfo) { Sema &SemaRef = state.getSema(); Declarator &D = state.getDeclarator(); QualType T; ReturnTypeInfo = 0; // The TagDecl owned by the DeclSpec. TagDecl *OwnedTagDecl = 0; switch (D.getName().getKind()) { case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: T = ConvertDeclSpecToType(state); if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { OwnedTagDecl = cast(D.getDeclSpec().getRepAsDecl()); // Owned declaration is embedded in declarator. OwnedTagDecl->setEmbeddedInDeclarator(true); } break; case UnqualifiedId::IK_ConstructorName: case UnqualifiedId::IK_ConstructorTemplateId: case UnqualifiedId::IK_DestructorName: // Constructors and destructors don't have return types. Use // "void" instead. T = SemaRef.Context.VoidTy; break; case UnqualifiedId::IK_ConversionFunctionId: // The result type of a conversion function is the type that it // converts to. T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId, &ReturnTypeInfo); break; } if (D.getAttributes()) distributeTypeAttrsFromDeclarator(state, T); // C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context. // In C++11, a function declarator using 'auto' must have a trailing return // type (this is checked later) and we can skip this. In other languages // using auto, we need to check regardless. if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && (!SemaRef.getLangOpts().CPlusPlus0x || !D.isFunctionDeclarator())) { int Error = -1; switch (D.getContext()) { case Declarator::KNRTypeListContext: llvm_unreachable("K&R type lists aren't allowed in C++"); case Declarator::LambdaExprContext: llvm_unreachable("Can't specify a type specifier in lambda grammar"); case Declarator::ObjCParameterContext: case Declarator::ObjCResultContext: case Declarator::PrototypeContext: Error = 0; // Function prototype break; case Declarator::MemberContext: if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) break; switch (cast(SemaRef.CurContext)->getTagKind()) { case TTK_Enum: llvm_unreachable("unhandled tag kind"); case TTK_Struct: Error = 1; /* Struct member */ break; case TTK_Union: Error = 2; /* Union member */ break; case TTK_Class: Error = 3; /* Class member */ break; } break; case Declarator::CXXCatchContext: case Declarator::ObjCCatchContext: Error = 4; // Exception declaration break; case Declarator::TemplateParamContext: Error = 5; // Template parameter break; case Declarator::BlockLiteralContext: Error = 6; // Block literal break; case Declarator::TemplateTypeArgContext: Error = 7; // Template type argument break; case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: Error = 9; // Type alias break; case Declarator::TrailingReturnContext: Error = 10; // Function return type break; case Declarator::TypeNameContext: Error = 11; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: case Declarator::ForContext: case Declarator::ConditionContext: case Declarator::CXXNewContext: break; } if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) Error = 8; // In Objective-C it is an error to use 'auto' on a function declarator. if (D.isFunctionDeclarator()) Error = 10; // C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator // contains a trailing return type. That is only legal at the outermost // level. Check all declarator chunks (outermost first) anyway, to give // better diagnostics. if (SemaRef.getLangOpts().CPlusPlus0x && Error != -1) { for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { unsigned chunkIndex = e - i - 1; state.setCurrentChunkIndex(chunkIndex); DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); if (DeclType.Kind == DeclaratorChunk::Function) { const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; if (FTI.TrailingReturnType) { Error = -1; break; } } } } if (Error != -1) { SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_not_allowed) << Error; T = SemaRef.Context.IntTy; D.setInvalidType(true); } else SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::warn_cxx98_compat_auto_type_specifier); } if (SemaRef.getLangOpts().CPlusPlus && OwnedTagDecl && OwnedTagDecl->isCompleteDefinition()) { // Check the contexts where C++ forbids the declaration of a new class // or enumeration in a type-specifier-seq. switch (D.getContext()) { case Declarator::TrailingReturnContext: // Class and enumeration definitions are syntactically not allowed in // trailing return types. llvm_unreachable("parser should not have allowed this"); break; case Declarator::FileContext: case Declarator::MemberContext: case Declarator::BlockContext: case Declarator::ForContext: case Declarator::BlockLiteralContext: case Declarator::LambdaExprContext: // C++11 [dcl.type]p3: // A type-specifier-seq shall not define a class or enumeration unless // it appears in the type-id of an alias-declaration (7.1.3) that is not // the declaration of a template-declaration. case Declarator::AliasDeclContext: break; case Declarator::AliasTemplateContext: SemaRef.Diag(OwnedTagDecl->getLocation(), diag::err_type_defined_in_alias_template) << SemaRef.Context.getTypeDeclType(OwnedTagDecl); break; case Declarator::TypeNameContext: case Declarator::TemplateParamContext: case Declarator::CXXNewContext: case Declarator::CXXCatchContext: case Declarator::ObjCCatchContext: case Declarator::TemplateTypeArgContext: SemaRef.Diag(OwnedTagDecl->getLocation(), diag::err_type_defined_in_type_specifier) << SemaRef.Context.getTypeDeclType(OwnedTagDecl); break; case Declarator::PrototypeContext: case Declarator::ObjCParameterContext: case Declarator::ObjCResultContext: case Declarator::KNRTypeListContext: // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. SemaRef.Diag(OwnedTagDecl->getLocation(), diag::err_type_defined_in_param_type) << SemaRef.Context.getTypeDeclType(OwnedTagDecl); break; case Declarator::ConditionContext: // C++ 6.4p2: // The type-specifier-seq shall not contain typedef and shall not declare // a new class or enumeration. SemaRef.Diag(OwnedTagDecl->getLocation(), diag::err_type_defined_in_condition); break; } } return T; } static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){ std::string Quals = Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString(); switch (FnTy->getRefQualifier()) { case RQ_None: break; case RQ_LValue: if (!Quals.empty()) Quals += ' '; Quals += '&'; break; case RQ_RValue: if (!Quals.empty()) Quals += ' '; Quals += "&&"; break; } return Quals; } /// Check that the function type T, which has a cv-qualifier or a ref-qualifier, /// can be contained within the declarator chunk DeclType, and produce an /// appropriate diagnostic if not. static void checkQualifiedFunction(Sema &S, QualType T, DeclaratorChunk &DeclType) { // C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: a function type with a // cv-qualifier or a ref-qualifier can only appear at the topmost level // of a type. int DiagKind = -1; switch (DeclType.Kind) { case DeclaratorChunk::Paren: case DeclaratorChunk::MemberPointer: // These cases are permitted. return; case DeclaratorChunk::Array: case DeclaratorChunk::Function: // These cases don't allow function types at all; no need to diagnose the // qualifiers separately. return; case DeclaratorChunk::BlockPointer: DiagKind = 0; break; case DeclaratorChunk::Pointer: DiagKind = 1; break; case DeclaratorChunk::Reference: DiagKind = 2; break; } assert(DiagKind != -1); S.Diag(DeclType.Loc, diag::err_compound_qualified_function_type) << DiagKind << isa(T.IgnoreParens()) << T << getFunctionQualifiersAsString(T->castAs()); } static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType declSpecType, TypeSourceInfo *TInfo) { QualType T = declSpecType; Declarator &D = state.getDeclarator(); Sema &S = state.getSema(); ASTContext &Context = S.Context; const LangOptions &LangOpts = S.getLangOpts(); bool ImplicitlyNoexcept = false; if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId && LangOpts.CPlusPlus0x) { OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator; /// In C++0x, deallocation functions (normal and array operator delete) /// are implicitly noexcept. if (OO == OO_Delete || OO == OO_Array_Delete) ImplicitlyNoexcept = true; } // The name we're declaring, if any. DeclarationName Name; if (D.getIdentifier()) Name = D.getIdentifier(); // Does this declaration declare a typedef-name? bool IsTypedefName = D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef || D.getContext() == Declarator::AliasDeclContext || D.getContext() == Declarator::AliasTemplateContext; // Does T refer to a function type with a cv-qualifier or a ref-qualifier? bool IsQualifiedFunction = T->isFunctionProtoType() && (T->castAs()->getTypeQuals() != 0 || T->castAs()->getRefQualifier() != RQ_None); // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { unsigned chunkIndex = e - i - 1; state.setCurrentChunkIndex(chunkIndex); DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); if (IsQualifiedFunction) { checkQualifiedFunction(S, T, DeclType); IsQualifiedFunction = DeclType.Kind == DeclaratorChunk::Paren; } switch (DeclType.Kind) { case DeclaratorChunk::Paren: T = S.BuildParenType(T); break; case DeclaratorChunk::BlockPointer: // If blocks are disabled, emit an error. if (!LangOpts.Blocks) S.Diag(DeclType.Loc, diag::err_blocks_disable); T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name); if (DeclType.Cls.TypeQuals) T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals); break; case DeclaratorChunk::Pointer: // Verify that we're not building a pointer to pointer to function with // exception specification. if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) { S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); D.setInvalidType(true); // Build the type anyway. } if (LangOpts.ObjC1 && T->getAs()) { T = Context.getObjCObjectPointerType(T); if (DeclType.Ptr.TypeQuals) T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); break; } T = S.BuildPointerType(T, DeclType.Loc, Name); if (DeclType.Ptr.TypeQuals) T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); break; case DeclaratorChunk::Reference: { // Verify that we're not building a reference to pointer to function with // exception specification. if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) { S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); D.setInvalidType(true); // Build the type anyway. } T = S.BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name); Qualifiers Quals; if (DeclType.Ref.HasRestrict) T = S.BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict); break; } case DeclaratorChunk::Array: { // Verify that we're not building an array of pointers to function with // exception specification. if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) { S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); D.setInvalidType(true); // Build the type anyway. } DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; Expr *ArraySize = static_cast(ATI.NumElts); ArrayType::ArraySizeModifier ASM; if (ATI.isStar) ASM = ArrayType::Star; else if (ATI.hasStatic) ASM = ArrayType::Static; else ASM = ArrayType::Normal; if (ASM == ArrayType::Star && !D.isPrototypeContext()) { // FIXME: This check isn't quite right: it allows star in prototypes // for function definitions, and disallows some edge cases detailed // in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html S.Diag(DeclType.Loc, diag::err_array_star_outside_prototype); ASM = ArrayType::Normal; D.setInvalidType(true); } T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; } case DeclaratorChunk::Function: { // If the function declarator has a prototype (i.e. it is not () and // does not have a K&R-style identifier list), then the arguments are part // of the type, otherwise the argument list is (). const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; IsQualifiedFunction = FTI.TypeQuals || FTI.hasRefQualifier(); // Check for auto functions and trailing return type and adjust the // return type accordingly. if (!D.isInvalidType()) { // trailing-return-type is only required if we're declaring a function, // and not, for instance, a pointer to a function. if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && !FTI.TrailingReturnType && chunkIndex == 0) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_missing_trailing_return); T = Context.IntTy; D.setInvalidType(true); } else if (FTI.TrailingReturnType) { // T must be exactly 'auto' at this point. See CWG issue 681. if (isa(T)) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_in_parens) << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } else if (D.getContext() != Declarator::LambdaExprContext && (T.hasQualifiers() || !isa(T))) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } T = S.GetTypeFromParser( ParsedType::getFromOpaquePtr(FTI.TrailingReturnType), &TInfo); } } // C99 6.7.5.3p1: The return type may not be a function or array type. // For conversion functions, we'll diagnose this particular error later. if ((T->isArrayType() || T->isFunctionType()) && (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { unsigned diagID = diag::err_func_returning_array_function; // Last processing chunk in block context means this function chunk // represents the block. if (chunkIndex == 0 && D.getContext() == Declarator::BlockLiteralContext) diagID = diag::err_block_returning_array_function; S.Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; T = Context.IntTy; D.setInvalidType(true); } // Do not allow returning half FP value. // FIXME: This really should be in BuildFunctionType. if (T->isHalfType()) { S.Diag(D.getIdentifierLoc(), diag::err_parameters_retval_cannot_have_fp16_type) << 1 << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); D.setInvalidType(true); } // cv-qualifiers on return types are pointless except when the type is a // class type in C++. if (isa(T) && T.getLocalCVRQualifiers() && (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) && (!LangOpts.CPlusPlus || !T->isDependentType())) { assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?"); DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1); assert(ReturnTypeChunk.Kind == DeclaratorChunk::Pointer); DeclaratorChunk::PointerTypeInfo &PTI = ReturnTypeChunk.Ptr; DiagnoseIgnoredQualifiers(PTI.TypeQuals, SourceLocation::getFromRawEncoding(PTI.ConstQualLoc), SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc), SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc), S); } else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() && (!LangOpts.CPlusPlus || (!T->isDependentType() && !T->isRecordType()))) { DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(), D.getDeclSpec().getConstSpecLoc(), D.getDeclSpec().getVolatileSpecLoc(), D.getDeclSpec().getRestrictSpecLoc(), S); } if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) { // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. TagDecl *Tag = cast(D.getDeclSpec().getRepAsDecl()); if (Tag->isCompleteDefinition()) S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type) << Context.getTypeDeclType(Tag); } // Exception specs are not allowed in typedefs. Complain, but add it // anyway. if (IsTypedefName && FTI.getExceptionSpecType()) S.Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) << (D.getContext() == Declarator::AliasDeclContext || D.getContext() == Declarator::AliasTemplateContext); if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T); } else { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" attribute. Scan // for this attribute now. if (!FTI.NumArgs && FTI.isVariadic && !LangOpts.CPlusPlus) { bool Overloadable = false; for (const AttributeList *Attrs = D.getAttributes(); Attrs; Attrs = Attrs->getNext()) { if (Attrs->getKind() == AttributeList::AT_overloadable) { Overloadable = true; break; } } if (!Overloadable) S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); } if (FTI.NumArgs && FTI.ArgInfo[0].Param == 0) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function // definition. S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); D.setInvalidType(true); break; } FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = FTI.isVariadic; EPI.HasTrailingReturn = FTI.TrailingReturnType; EPI.TypeQuals = FTI.TypeQuals; EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None : FTI.RefQualifierIsLValueRef? RQ_LValue : RQ_RValue; // Otherwise, we have a function with an argument list that is // potentially variadic. SmallVector ArgTys; ArgTys.reserve(FTI.NumArgs); SmallVector ConsumedArguments; ConsumedArguments.reserve(FTI.NumArgs); bool HasAnyConsumedArguments = false; for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast(FTI.ArgInfo[i].Param); QualType ArgTy = Param->getType(); assert(!ArgTy.isNull() && "Couldn't parse type?"); // Adjust the parameter type. assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) && "Unadjusted type?"); // Look for 'void'. void is allowed only as a single argument to a // function with no other parameters (C99 6.7.5.3p10). We record // int(void) as a FunctionProtoType with an empty argument list. if (ArgTy->isVoidType()) { // If this is something like 'float(int, void)', reject it. 'void' // is an incomplete type (C99 6.2.5p19) and function decls cannot // have arguments of incomplete type. if (FTI.NumArgs != 1 || FTI.isVariadic) { S.Diag(DeclType.Loc, diag::err_void_only_param); ArgTy = Context.IntTy; Param->setType(ArgTy); } else if (FTI.ArgInfo[i].Ident) { // Reject, but continue to parse 'int(void abc)'. S.Diag(FTI.ArgInfo[i].IdentLoc, diag::err_param_with_void_type); ArgTy = Context.IntTy; Param->setType(ArgTy); } else { // Reject, but continue to parse 'float(const void)'. if (ArgTy.hasQualifiers()) S.Diag(DeclType.Loc, diag::err_void_param_qualified); // Do not add 'void' to the ArgTys list. break; } } else if (ArgTy->isHalfType()) { // Disallow half FP arguments. // FIXME: This really should be in BuildFunctionType. S.Diag(Param->getLocation(), diag::err_parameters_retval_cannot_have_fp16_type) << 0 << FixItHint::CreateInsertion(Param->getLocation(), "*"); D.setInvalidType(); } else if (!FTI.hasPrototype) { if (ArgTy->isPromotableIntegerType()) { ArgTy = Context.getPromotedIntegerType(ArgTy); Param->setKNRPromoted(true); } else if (const BuiltinType* BTy = ArgTy->getAs()) { if (BTy->getKind() == BuiltinType::Float) { ArgTy = Context.DoubleTy; Param->setKNRPromoted(true); } } } if (LangOpts.ObjCAutoRefCount) { bool Consumed = Param->hasAttr(); ConsumedArguments.push_back(Consumed); HasAnyConsumedArguments |= Consumed; } ArgTys.push_back(ArgTy); } if (HasAnyConsumedArguments) EPI.ConsumedArguments = ConsumedArguments.data(); SmallVector Exceptions; SmallVector DynamicExceptions; SmallVector DynamicExceptionRanges; Expr *NoexceptExpr = 0; if (FTI.getExceptionSpecType() == EST_Dynamic) { // FIXME: It's rather inefficient to have to split into two vectors // here. unsigned N = FTI.NumExceptions; DynamicExceptions.reserve(N); DynamicExceptionRanges.reserve(N); for (unsigned I = 0; I != N; ++I) { DynamicExceptions.push_back(FTI.Exceptions[I].Ty); DynamicExceptionRanges.push_back(FTI.Exceptions[I].Range); } } else if (FTI.getExceptionSpecType() == EST_ComputedNoexcept) { NoexceptExpr = FTI.NoexceptExpr; } S.checkExceptionSpecification(FTI.getExceptionSpecType(), DynamicExceptions, DynamicExceptionRanges, NoexceptExpr, Exceptions, EPI); if (FTI.getExceptionSpecType() == EST_None && ImplicitlyNoexcept && chunkIndex == 0) { // Only the outermost chunk is marked noexcept, of course. EPI.ExceptionSpecType = EST_BasicNoexcept; } T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI); } break; } case DeclaratorChunk::MemberPointer: // The scope spec must refer to a class, or be dependent. CXXScopeSpec &SS = DeclType.Mem.Scope(); QualType ClsType; if (SS.isInvalid()) { // Avoid emitting extra errors if we already errored on the scope. D.setInvalidType(true); } else if (S.isDependentScopeSpecifier(SS) || dyn_cast_or_null(S.computeDeclContext(SS))) { NestedNameSpecifier *NNS = static_cast(SS.getScopeRep()); NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: ClsType = Context.getDependentNameType(ETK_None, NNSPrefix, NNS->getAsIdentifier()); break; case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: llvm_unreachable("Nested-name-specifier must name a type"); case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: ClsType = QualType(NNS->getAsType(), 0); // Note: if the NNS has a prefix and ClsType is a nondependent // TemplateSpecializationType, then the NNS prefix is NOT included // in ClsType; hence we wrap ClsType into an ElaboratedType. // NOTE: in particular, no wrap occurs if ClsType already is an // Elaborated, DependentName, or DependentTemplateSpecialization. if (NNSPrefix && isa(NNS->getAsType())) ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType); break; } } else { S.Diag(DeclType.Mem.Scope().getBeginLoc(), diag::err_illegal_decl_mempointer_in_nonclass) << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name") << DeclType.Mem.Scope().getRange(); D.setInvalidType(true); } if (!ClsType.isNull()) T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier()); if (T.isNull()) { T = Context.IntTy; D.setInvalidType(true); } else if (DeclType.Mem.TypeQuals) { T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals); } break; } if (T.isNull()) { D.setInvalidType(true); T = Context.IntTy; } // See if there are any attributes on this declarator chunk. if (AttributeList *attrs = const_cast(DeclType.getAttrs())) processTypeAttrs(state, T, false, attrs); } if (LangOpts.CPlusPlus && T->isFunctionType()) { const FunctionProtoType *FnTy = T->getAs(); assert(FnTy && "Why oh why is there not a FunctionProtoType here?"); // C++ 8.3.5p4: // A cv-qualifier-seq shall only be part of the function type // for a nonstatic member function, the function type to which a pointer // to member refers, or the top-level function type of a function typedef // declaration. // // Core issue 547 also allows cv-qualifiers on function types that are // top-level template type arguments. bool FreeFunction; if (!D.getCXXScopeSpec().isSet()) { FreeFunction = ((D.getContext() != Declarator::MemberContext && D.getContext() != Declarator::LambdaExprContext) || D.getDeclSpec().isFriendSpecified()); } else { DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec()); FreeFunction = (DC && !DC->isRecord()); } // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member // function that is not a constructor declares that function to be const. if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static && D.getName().getKind() != UnqualifiedId::IK_ConstructorName && D.getName().getKind() != UnqualifiedId::IK_ConstructorTemplateId && !(FnTy->getTypeQuals() & DeclSpec::TQ_const)) { // Rebuild function type adding a 'const' qualifier. FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); EPI.TypeQuals |= DeclSpec::TQ_const; T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), FnTy->getNumArgs(), EPI); } // C++11 [dcl.fct]p6 (w/DR1417): // An attempt to specify a function type with a cv-qualifier-seq or a // ref-qualifier (including by typedef-name) is ill-formed unless it is: // - the function type for a non-static member function, // - the function type to which a pointer to member refers, // - the top-level function type of a function typedef declaration or // alias-declaration, // - the type-id in the default argument of a type-parameter, or // - the type-id of a template-argument for a type-parameter if (IsQualifiedFunction && !(!FreeFunction && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) && !IsTypedefName && D.getContext() != Declarator::TemplateTypeArgContext) { SourceLocation Loc = D.getLocStart(); SourceRange RemovalRange; unsigned I; if (D.isFunctionDeclarator(I)) { SmallVector RemovalLocs; const DeclaratorChunk &Chunk = D.getTypeObject(I); assert(Chunk.Kind == DeclaratorChunk::Function); if (Chunk.Fun.hasRefQualifier()) RemovalLocs.push_back(Chunk.Fun.getRefQualifierLoc()); if (Chunk.Fun.TypeQuals & Qualifiers::Const) RemovalLocs.push_back(Chunk.Fun.getConstQualifierLoc()); if (Chunk.Fun.TypeQuals & Qualifiers::Volatile) RemovalLocs.push_back(Chunk.Fun.getVolatileQualifierLoc()); // FIXME: We do not track the location of the __restrict qualifier. //if (Chunk.Fun.TypeQuals & Qualifiers::Restrict) // RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc()); if (!RemovalLocs.empty()) { std::sort(RemovalLocs.begin(), RemovalLocs.end(), SourceManager::LocBeforeThanCompare(S.getSourceManager())); RemovalRange = SourceRange(RemovalLocs.front(), RemovalLocs.back()); Loc = RemovalLocs.front(); } } S.Diag(Loc, diag::err_invalid_qualified_function_type) << FreeFunction << D.isFunctionDeclarator() << T << getFunctionQualifiersAsString(FnTy) << FixItHint::CreateRemoval(RemovalRange); // Strip the cv-qualifiers and ref-qualifiers from the type. FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); EPI.TypeQuals = 0; EPI.RefQualifier = RQ_None; T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), FnTy->getNumArgs(), EPI); } } // Apply any undistributed attributes from the declarator. if (!T.isNull()) if (AttributeList *attrs = D.getAttributes()) processTypeAttrs(state, T, false, attrs); // Diagnose any ignored type attributes. if (!T.isNull()) state.diagnoseIgnoredTypeAttrs(T); // C++0x [dcl.constexpr]p9: // A constexpr specifier used in an object declaration declares the object // as const. if (D.getDeclSpec().isConstexprSpecified() && T->isObjectType()) { T.addConst(); } // If there was an ellipsis in the declarator, the declaration declares a // parameter pack whose type may be a pack expansion type. if (D.hasEllipsis() && !T.isNull()) { // C++0x [dcl.fct]p13: // A declarator-id or abstract-declarator containing an ellipsis shall // only be used in a parameter-declaration. Such a parameter-declaration // is a parameter pack (14.5.3). [...] switch (D.getContext()) { case Declarator::PrototypeContext: // C++0x [dcl.fct]p13: // [...] When it is part of a parameter-declaration-clause, the // parameter pack is a function parameter pack (14.5.3). The type T // of the declarator-id of the function parameter pack shall contain // a template parameter pack; each template parameter pack in T is // expanded by the function parameter pack. // // We represent function parameter packs as function parameters whose // type is a pack expansion. if (!T->containsUnexpandedParameterPack()) { S.Diag(D.getEllipsisLoc(), diag::err_function_parameter_pack_without_parameter_packs) << T << D.getSourceRange(); D.setEllipsisLoc(SourceLocation()); } else { T = Context.getPackExpansionType(T, llvm::Optional()); } break; case Declarator::TemplateParamContext: // C++0x [temp.param]p15: // If a template-parameter is a [...] is a parameter-declaration that // declares a parameter pack (8.3.5), then the template-parameter is a // template parameter pack (14.5.3). // // Note: core issue 778 clarifies that, if there are any unexpanded // parameter packs in the type of the non-type template parameter, then // it expands those parameter packs. if (T->containsUnexpandedParameterPack()) T = Context.getPackExpansionType(T, llvm::Optional()); else S.Diag(D.getEllipsisLoc(), LangOpts.CPlusPlus0x ? diag::warn_cxx98_compat_variadic_templates : diag::ext_variadic_templates); break; case Declarator::FileContext: case Declarator::KNRTypeListContext: case Declarator::ObjCParameterContext: // FIXME: special diagnostic here? case Declarator::ObjCResultContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: case Declarator::CXXNewContext: case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: case Declarator::MemberContext: case Declarator::BlockContext: case Declarator::ForContext: case Declarator::ConditionContext: case Declarator::CXXCatchContext: case Declarator::ObjCCatchContext: case Declarator::BlockLiteralContext: case Declarator::LambdaExprContext: case Declarator::TrailingReturnContext: case Declarator::TemplateTypeArgContext: // FIXME: We may want to allow parameter packs in block-literal contexts // in the future. S.Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter); D.setEllipsisLoc(SourceLocation()); break; } } if (T.isNull()) return Context.getNullTypeSourceInfo(); else if (D.isInvalidType()) return Context.getTrivialTypeSourceInfo(T); return S.GetTypeSourceInfoForDeclarator(D, T, TInfo); } /// GetTypeForDeclarator - Convert the type for the specified /// declarator to Type instances. /// /// The result of this call will never be null, but the associated /// type may be a null type if there's an unrecoverable error. TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { // Determine the type of the declarator. Not all forms of declarator // have a type. TypeProcessingState state(*this, D); TypeSourceInfo *ReturnTypeInfo = 0; QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); if (T.isNull()) return Context.getNullTypeSourceInfo(); if (D.isPrototypeContext() && getLangOpts().ObjCAutoRefCount) inferARCWriteback(state, T); return GetFullTypeForDeclarator(state, T, ReturnTypeInfo); } static void transferARCOwnershipToDeclSpec(Sema &S, QualType &declSpecTy, Qualifiers::ObjCLifetime ownership) { if (declSpecTy->isObjCRetainableType() && declSpecTy.getObjCLifetime() == Qualifiers::OCL_None) { Qualifiers qs; qs.addObjCLifetime(ownership); declSpecTy = S.Context.getQualifiedType(declSpecTy, qs); } } static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, Qualifiers::ObjCLifetime ownership, unsigned chunkIndex) { Sema &S = state.getSema(); Declarator &D = state.getDeclarator(); // Look for an explicit lifetime attribute. DeclaratorChunk &chunk = D.getTypeObject(chunkIndex); for (const AttributeList *attr = chunk.getAttrs(); attr; attr = attr->getNext()) if (attr->getKind() == AttributeList::AT_objc_ownership) return; const char *attrStr = 0; switch (ownership) { case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); case Qualifiers::OCL_ExplicitNone: attrStr = "none"; break; case Qualifiers::OCL_Strong: attrStr = "strong"; break; case Qualifiers::OCL_Weak: attrStr = "weak"; break; case Qualifiers::OCL_Autoreleasing: attrStr = "autoreleasing"; break; } // If there wasn't one, add one (with an invalid source location // so that we don't make an AttributedType for it). AttributeList *attr = D.getAttributePool() .create(&S.Context.Idents.get("objc_ownership"), SourceLocation(), /*scope*/ 0, SourceLocation(), &S.Context.Idents.get(attrStr), SourceLocation(), /*args*/ 0, 0, /*declspec*/ false, /*C++0x*/ false); spliceAttrIntoList(*attr, chunk.getAttrListRef()); // TODO: mark whether we did this inference? } /// \brief Used for transfering ownership in casts resulting in l-values. static void transferARCOwnership(TypeProcessingState &state, QualType &declSpecTy, Qualifiers::ObjCLifetime ownership) { Sema &S = state.getSema(); Declarator &D = state.getDeclarator(); int inner = -1; bool hasIndirection = false; for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorChunk &chunk = D.getTypeObject(i); switch (chunk.Kind) { case DeclaratorChunk::Paren: // Ignore parens. break; case DeclaratorChunk::Array: case DeclaratorChunk::Reference: case DeclaratorChunk::Pointer: if (inner != -1) hasIndirection = true; inner = i; break; case DeclaratorChunk::BlockPointer: if (inner != -1) transferARCOwnershipToDeclaratorChunk(state, ownership, i); return; case DeclaratorChunk::Function: case DeclaratorChunk::MemberPointer: return; } } if (inner == -1) return; DeclaratorChunk &chunk = D.getTypeObject(inner); if (chunk.Kind == DeclaratorChunk::Pointer) { if (declSpecTy->isObjCRetainableType()) return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership); if (declSpecTy->isObjCObjectType() && hasIndirection) return transferARCOwnershipToDeclaratorChunk(state, ownership, inner); } else { assert(chunk.Kind == DeclaratorChunk::Array || chunk.Kind == DeclaratorChunk::Reference); return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership); } } TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) { TypeProcessingState state(*this, D); TypeSourceInfo *ReturnTypeInfo = 0; QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); if (declSpecTy.isNull()) return Context.getNullTypeSourceInfo(); if (getLangOpts().ObjCAutoRefCount) { Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy); if (ownership != Qualifiers::OCL_None) transferARCOwnership(state, declSpecTy, ownership); } return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo); } /// Map an AttributedType::Kind to an AttributeList::Kind. static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { switch (kind) { case AttributedType::attr_address_space: return AttributeList::AT_address_space; case AttributedType::attr_regparm: return AttributeList::AT_regparm; case AttributedType::attr_vector_size: return AttributeList::AT_vector_size; case AttributedType::attr_neon_vector_type: return AttributeList::AT_neon_vector_type; case AttributedType::attr_neon_polyvector_type: return AttributeList::AT_neon_polyvector_type; case AttributedType::attr_objc_gc: return AttributeList::AT_objc_gc; case AttributedType::attr_objc_ownership: return AttributeList::AT_objc_ownership; case AttributedType::attr_noreturn: return AttributeList::AT_noreturn; case AttributedType::attr_cdecl: return AttributeList::AT_cdecl; case AttributedType::attr_fastcall: return AttributeList::AT_fastcall; case AttributedType::attr_stdcall: return AttributeList::AT_stdcall; case AttributedType::attr_thiscall: return AttributeList::AT_thiscall; case AttributedType::attr_pascal: return AttributeList::AT_pascal; case AttributedType::attr_pcs: return AttributeList::AT_pcs; } llvm_unreachable("unexpected attribute kind!"); } static void fillAttributedTypeLoc(AttributedTypeLoc TL, const AttributeList *attrs) { AttributedType::Kind kind = TL.getAttrKind(); assert(attrs && "no type attributes in the expected location!"); AttributeList::Kind parsedKind = getAttrListKind(kind); while (attrs->getKind() != parsedKind) { attrs = attrs->getNext(); assert(attrs && "no matching attribute in expected location!"); } TL.setAttrNameLoc(attrs->getLoc()); if (TL.hasAttrExprOperand()) TL.setAttrExprOperand(attrs->getArg(0)); else if (TL.hasAttrEnumOperand()) TL.setAttrEnumOperandLoc(attrs->getParameterLoc()); // FIXME: preserve this information to here. if (TL.hasAttrOperand()) TL.setAttrOperandParensRange(SourceRange()); } namespace { class TypeSpecLocFiller : public TypeLocVisitor { ASTContext &Context; const DeclSpec &DS; public: TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS) : Context(Context), DS(DS) {} void VisitAttributedTypeLoc(AttributedTypeLoc TL) { fillAttributedTypeLoc(TL, DS.getAttributes().getList()); Visit(TL.getModifiedLoc()); } void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); } void VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); } void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); } void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { // Handle the base type, which might not have been written explicitly. if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { TL.setHasBaseTypeAsWritten(false); TL.getBaseLoc().initialize(Context, SourceLocation()); } else { TL.setHasBaseTypeAsWritten(true); Visit(TL.getBaseLoc()); } // Protocol qualifiers. if (DS.getProtocolQualifiers()) { assert(TL.getNumProtocols() > 0); assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); TL.setLAngleLoc(DS.getProtocolLAngleLoc()); TL.setRAngleLoc(DS.getSourceRange().getEnd()); for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); } else { assert(TL.getNumProtocols() == 0); TL.setLAngleLoc(SourceLocation()); TL.setRAngleLoc(SourceLocation()); } } void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setStarLoc(SourceLocation()); Visit(TL.getPointeeLoc()); } void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { TypeSourceInfo *TInfo = 0; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); // If we got no declarator info from previous Sema routines, // just fill with the typespec loc. if (!TInfo) { TL.initialize(Context, DS.getTypeSpecTypeNameLoc()); return; } TypeLoc OldTL = TInfo->getTypeLoc(); if (TInfo->getType()->getAs()) { ElaboratedTypeLoc ElabTL = cast(OldTL); TemplateSpecializationTypeLoc NamedTL = cast(ElabTL.getNamedTypeLoc()); TL.copy(NamedTL); } else TL.copy(cast(OldTL)); } void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr); TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); } void VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType); TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); assert(DS.getRepAsType()); TypeSourceInfo *TInfo = 0; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); TL.setUnderlyingTInfo(TInfo); } void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { // FIXME: This holds only because we only have one unary transform. assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType); TL.setKWLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); assert(DS.getRepAsType()); TypeSourceInfo *TInfo = 0; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); TL.setUnderlyingTInfo(TInfo); } void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { // By default, use the source location of the type specifier. TL.setBuiltinLoc(DS.getTypeSpecTypeLoc()); if (TL.needsExtraLocalData()) { // Set info for the written builtin specifiers. TL.getWrittenBuiltinSpecs() = DS.getWrittenBuiltinSpecs(); // Try to have a meaningful source location. if (TL.getWrittenSignSpec() != TSS_unspecified) // Sign spec loc overrides the others (e.g., 'unsigned long'). TL.setBuiltinLoc(DS.getTypeSpecSignLoc()); else if (TL.getWrittenWidthSpec() != TSW_unspecified) // Width spec loc overrides type spec loc (e.g., 'short int'). TL.setBuiltinLoc(DS.getTypeSpecWidthLoc()); } } void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { ElaboratedTypeKeyword Keyword = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType()); if (DS.getTypeSpecType() == TST_typename) { TypeSourceInfo *TInfo = 0; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); if (TInfo) { TL.copy(cast(TInfo->getTypeLoc())); return; } } TL.setElaboratedKeywordLoc(Keyword != ETK_None ? DS.getTypeSpecTypeLoc() : SourceLocation()); const CXXScopeSpec& SS = DS.getTypeSpecScope(); TL.setQualifierLoc(SS.getWithLocInContext(Context)); Visit(TL.getNextTypeLoc().getUnqualifiedLoc()); } void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { assert(DS.getTypeSpecType() == TST_typename); TypeSourceInfo *TInfo = 0; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); assert(TInfo); TL.copy(cast(TInfo->getTypeLoc())); } void VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { assert(DS.getTypeSpecType() == TST_typename); TypeSourceInfo *TInfo = 0; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); assert(TInfo); TL.copy(cast( TInfo->getTypeLoc())); } void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } void VisitAtomicTypeLoc(AtomicTypeLoc TL) { TL.setKWLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); TypeSourceInfo *TInfo = 0; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(Context, DS.getTypeSpecTypeLoc()); } }; class DeclaratorLocFiller : public TypeLocVisitor { ASTContext &Context; const DeclaratorChunk &Chunk; public: DeclaratorLocFiller(ASTContext &Context, const DeclaratorChunk &Chunk) : Context(Context), Chunk(Chunk) {} void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { llvm_unreachable("qualified type locs not expected here!"); } void VisitAttributedTypeLoc(AttributedTypeLoc TL) { fillAttributedTypeLoc(TL, Chunk.getAttrs()); } void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::BlockPointer); TL.setCaretLoc(Chunk.Loc); } void VisitPointerTypeLoc(PointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Pointer); TL.setStarLoc(Chunk.Loc); } void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Pointer); TL.setStarLoc(Chunk.Loc); } void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::MemberPointer); const CXXScopeSpec& SS = Chunk.Mem.Scope(); NestedNameSpecifierLoc NNSLoc = SS.getWithLocInContext(Context); const Type* ClsTy = TL.getClass(); QualType ClsQT = QualType(ClsTy, 0); TypeSourceInfo *ClsTInfo = Context.CreateTypeSourceInfo(ClsQT, 0); // Now copy source location info into the type loc component. TypeLoc ClsTL = ClsTInfo->getTypeLoc(); switch (NNSLoc.getNestedNameSpecifier()->getKind()) { case NestedNameSpecifier::Identifier: assert(isa(ClsTy) && "Unexpected TypeLoc"); { DependentNameTypeLoc DNTLoc = cast(ClsTL); DNTLoc.setElaboratedKeywordLoc(SourceLocation()); DNTLoc.setQualifierLoc(NNSLoc.getPrefix()); DNTLoc.setNameLoc(NNSLoc.getLocalBeginLoc()); } break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: if (isa(ClsTy)) { ElaboratedTypeLoc ETLoc = *cast(&ClsTL); ETLoc.setElaboratedKeywordLoc(SourceLocation()); ETLoc.setQualifierLoc(NNSLoc.getPrefix()); TypeLoc NamedTL = ETLoc.getNamedTypeLoc(); NamedTL.initializeFullCopy(NNSLoc.getTypeLoc()); } else { ClsTL.initializeFullCopy(NNSLoc.getTypeLoc()); } break; case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: llvm_unreachable("Nested-name-specifier must name a type"); } // Finally fill in MemberPointerLocInfo fields. TL.setStarLoc(Chunk.Loc); TL.setClassTInfo(ClsTInfo); } void VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Reference); // 'Amp' is misleading: this might have been originally /// spelled with AmpAmp. TL.setAmpLoc(Chunk.Loc); } void VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Reference); assert(!Chunk.Ref.LValueRef); TL.setAmpAmpLoc(Chunk.Loc); } void VisitArrayTypeLoc(ArrayTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Array); TL.setLBracketLoc(Chunk.Loc); TL.setRBracketLoc(Chunk.EndLoc); TL.setSizeExpr(static_cast(Chunk.Arr.NumElts)); } void VisitFunctionTypeLoc(FunctionTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Function); TL.setLocalRangeBegin(Chunk.Loc); TL.setLocalRangeEnd(Chunk.EndLoc); TL.setTrailingReturn(!!Chunk.Fun.TrailingReturnType); const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun; for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) { ParmVarDecl *Param = cast(FTI.ArgInfo[i].Param); TL.setArg(tpi++, Param); } // FIXME: exception specs } void VisitParenTypeLoc(ParenTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Paren); TL.setLParenLoc(Chunk.Loc); TL.setRParenLoc(Chunk.EndLoc); } void VisitTypeLoc(TypeLoc TL) { llvm_unreachable("unsupported TypeLoc kind in declarator!"); } }; } /// \brief Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. /// /// \param ReturnTypeInfo For declarators whose return type does not show /// up in the normal place in the declaration specifiers (such as a C++ /// conversion function), this pointer will refer to a type source information /// for that return type. TypeSourceInfo * Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *ReturnTypeInfo) { TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); // Handle parameter packs whose type is a pack expansion. if (isa(T)) { cast(CurrTL).setEllipsisLoc(D.getEllipsisLoc()); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { while (isa(CurrTL)) { AttributedTypeLoc TL = cast(CurrTL); fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs()); CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); } DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); } // If we have different source information for the return type, use // that. This really only applies to C++ conversion functions. if (ReturnTypeInfo) { TypeLoc TL = ReturnTypeInfo->getTypeLoc(); assert(TL.getFullDataSize() == CurrTL.getFullDataSize()); memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize()); } else { TypeSpecLocFiller(Context, D.getDeclSpec()).Visit(CurrTL); } return TInfo; } /// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo. ParsedType Sema::CreateParsedType(QualType T, TypeSourceInfo *TInfo) { // FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser // and Sema during declaration parsing. Try deallocating/caching them when // it's appropriate, instead of allocating them and keeping them around. LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType), TypeAlignment); new (LocT) LocInfoType(T, TInfo); assert(LocT->getTypeClass() != T->getTypeClass() && "LocInfoType's TypeClass conflicts with an existing Type class"); return ParsedType::make(QualType(LocT, 0)); } void LocInfoType::getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const { llvm_unreachable("LocInfoType leaked into the type system; an opaque TypeTy*" " was used directly instead of getting the QualType through" " GetTypeFromParser"); } TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // C99 6.7.6: Type names have no identifier. This is already validated by // the parser. assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); if (D.isInvalidType()) return true; // Make sure there are no unused decl attributes on the declarator. // We don't want to do this for ObjC parameters because we're going // to apply them to the actual parameter declaration. if (D.getContext() != Declarator::ObjCParameterContext) checkUnusedDeclAttributes(D); if (getLangOpts().CPlusPlus) { // Check that there are no default arguments (C++ only). CheckExtraCXXDefaultArguments(D); } return CreateParsedType(T, TInfo); } ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) { QualType T = Context.getObjCInstanceType(); TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(T, Loc); return CreateParsedType(T, TInfo); } //===----------------------------------------------------------------------===// // Type Attribute Processing //===----------------------------------------------------------------------===// /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S){ // If this type is already address space qualified, reject it. // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by // qualifiers for two or more different address spaces." if (Type.getAddressSpace()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); Attr.setInvalid(); return; } // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be // qualified by an address-space qualifier." if (Type->isFunctionType()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_function_type); Attr.setInvalid(); return; } // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; Attr.setInvalid(); return; } Expr *ASArgExpr = static_cast(Attr.getArg(0)); llvm::APSInt addrSpace(32); if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() || !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int) << ASArgExpr->getSourceRange(); Attr.setInvalid(); return; } // Bounds checking. if (addrSpace.isSigned()) { if (addrSpace.isNegative()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative) << ASArgExpr->getSourceRange(); Attr.setInvalid(); return; } addrSpace.setIsSigned(false); } llvm::APSInt max(addrSpace.getBitWidth()); max = Qualifiers::MaxAddressSpace; if (addrSpace > max) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high) << Qualifiers::MaxAddressSpace << ASArgExpr->getSourceRange(); Attr.setInvalid(); return; } unsigned ASIdx = static_cast(addrSpace.getZExtValue()); Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } /// Does this type have a "direct" ownership qualifier? That is, /// is it written like "__strong id", as opposed to something like /// "typeof(foo)", where that happens to be strong? static bool hasDirectOwnershipQualifier(QualType type) { // Fast path: no qualifier at all. assert(type.getQualifiers().hasObjCLifetime()); while (true) { // __strong id if (const AttributedType *attr = dyn_cast(type)) { if (attr->getAttrKind() == AttributedType::attr_objc_ownership) return true; type = attr->getModifiedType(); // X *__strong (...) } else if (const ParenType *paren = dyn_cast(type)) { type = paren->getInnerType(); // That's it for things we want to complain about. In particular, // we do not want to look through typedefs, typeof(expr), // typeof(type), or any other way that the type is somehow // abstracted. } else { return false; } } } /// handleObjCOwnershipTypeAttr - Process an objc_ownership /// attribute on the specified type. /// /// Returns 'true' if the attribute was handled. static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type) { bool NonObjCPointer = false; if (!type->isDependentType()) { if (const PointerType *ptr = type->getAs()) { QualType pointee = ptr->getPointeeType(); if (pointee->isObjCRetainableType() || pointee->isPointerType()) return false; // It is important not to lose the source info that there was an attribute // applied to non-objc pointer. We will create an attributed type but // its type will be the same as the original type. NonObjCPointer = true; } else if (!type->isObjCRetainableType()) { return false; } } Sema &S = state.getSema(); SourceLocation AttrLoc = attr.getLoc(); if (AttrLoc.isMacroID()) AttrLoc = S.getSourceManager().getImmediateExpansionRange(AttrLoc).first; if (!attr.getParameterName()) { S.Diag(AttrLoc, diag::err_attribute_argument_n_not_string) << "objc_ownership" << 1; attr.setInvalid(); return true; } // Consume lifetime attributes without further comment outside of // ARC mode. if (!S.getLangOpts().ObjCAutoRefCount) return true; Qualifiers::ObjCLifetime lifetime; if (attr.getParameterName()->isStr("none")) lifetime = Qualifiers::OCL_ExplicitNone; else if (attr.getParameterName()->isStr("strong")) lifetime = Qualifiers::OCL_Strong; else if (attr.getParameterName()->isStr("weak")) lifetime = Qualifiers::OCL_Weak; else if (attr.getParameterName()->isStr("autoreleasing")) lifetime = Qualifiers::OCL_Autoreleasing; else { S.Diag(AttrLoc, diag::warn_attribute_type_not_supported) << "objc_ownership" << attr.getParameterName(); attr.setInvalid(); return true; } SplitQualType underlyingType = type.split(); // Check for redundant/conflicting ownership qualifiers. if (Qualifiers::ObjCLifetime previousLifetime = type.getQualifiers().getObjCLifetime()) { // If it's written directly, that's an error. if (hasDirectOwnershipQualifier(type)) { S.Diag(AttrLoc, diag::err_attr_objc_ownership_redundant) << type; return true; } // Otherwise, if the qualifiers actually conflict, pull sugar off // until we reach a type that is directly qualified. if (previousLifetime != lifetime) { // This should always terminate: the canonical type is // qualified, so some bit of sugar must be hiding it. while (!underlyingType.Quals.hasObjCLifetime()) { underlyingType = underlyingType.getSingleStepDesugaredType(); } underlyingType.Quals.removeObjCLifetime(); } } underlyingType.Quals.addObjCLifetime(lifetime); if (NonObjCPointer) { StringRef name = attr.getName()->getName(); switch (lifetime) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: break; case Qualifiers::OCL_Strong: name = "__strong"; break; case Qualifiers::OCL_Weak: name = "__weak"; break; case Qualifiers::OCL_Autoreleasing: name = "__autoreleasing"; break; } S.Diag(AttrLoc, diag::warn_objc_object_attribute_wrong_type) << name << type; } QualType origType = type; if (!NonObjCPointer) type = S.Context.getQualifiedType(underlyingType); // If we have a valid source location for the attribute, use an // AttributedType instead. if (AttrLoc.isValid()) type = S.Context.getAttributedType(AttributedType::attr_objc_ownership, origType, type); // Forbid __weak if the runtime doesn't support it. if (lifetime == Qualifiers::OCL_Weak && !S.getLangOpts().ObjCRuntimeHasWeak && !NonObjCPointer) { // Actually, delay this until we know what we're parsing. if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { S.DelayedDiagnostics.add( sema::DelayedDiagnostic::makeForbiddenType( S.getSourceManager().getExpansionLoc(AttrLoc), diag::err_arc_weak_no_runtime, type, /*ignored*/ 0)); } else { S.Diag(AttrLoc, diag::err_arc_weak_no_runtime); } attr.setInvalid(); return true; } // Forbid __weak for class objects marked as // objc_arc_weak_reference_unavailable if (lifetime == Qualifiers::OCL_Weak) { QualType T = type; while (const PointerType *ptr = T->getAs()) T = ptr->getPointeeType(); if (const ObjCObjectPointerType *ObjT = T->getAs()) { ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); if (Class->isArcWeakrefUnavailable()) { S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class); S.Diag(ObjT->getInterfaceDecl()->getLocation(), diag::note_class_declared); } } } return true; } /// handleObjCGCTypeAttr - Process the __attribute__((objc_gc)) type /// attribute on the specified type. Returns true to indicate that /// the attribute was handled, false to indicate that the type does /// not permit the attribute. static bool handleObjCGCTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type) { Sema &S = state.getSema(); // Delay if this isn't some kind of pointer. if (!type->isPointerType() && !type->isObjCObjectPointerType() && !type->isBlockPointerType()) return false; if (type.getObjCGCAttr() != Qualifiers::GCNone) { S.Diag(attr.getLoc(), diag::err_attribute_multiple_objc_gc); attr.setInvalid(); return true; } // Check the attribute arguments. if (!attr.getParameterName()) { S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) << "objc_gc" << 1; attr.setInvalid(); return true; } Qualifiers::GC GCAttr; if (attr.getNumArgs() != 0) { S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; attr.setInvalid(); return true; } if (attr.getParameterName()->isStr("weak")) GCAttr = Qualifiers::Weak; else if (attr.getParameterName()->isStr("strong")) GCAttr = Qualifiers::Strong; else { S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported) << "objc_gc" << attr.getParameterName(); attr.setInvalid(); return true; } QualType origType = type; type = S.Context.getObjCGCQualType(origType, GCAttr); // Make an attributed type to preserve the source information. if (attr.getLoc().isValid()) type = S.Context.getAttributedType(AttributedType::attr_objc_gc, origType, type); return true; } namespace { /// A helper class to unwrap a type down to a function for the /// purposes of applying attributes there. /// /// Use: /// FunctionTypeUnwrapper unwrapped(SemaRef, T); /// if (unwrapped.isFunctionType()) { /// const FunctionType *fn = unwrapped.get(); /// // change fn somehow /// T = unwrapped.wrap(fn); /// } struct FunctionTypeUnwrapper { enum WrapKind { Desugar, Parens, Pointer, BlockPointer, Reference, MemberPointer }; QualType Original; const FunctionType *Fn; SmallVector Stack; FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) { while (true) { const Type *Ty = T.getTypePtr(); if (isa(Ty)) { Fn = cast(Ty); return; } else if (isa(Ty)) { T = cast(Ty)->getInnerType(); Stack.push_back(Parens); } else if (isa(Ty)) { T = cast(Ty)->getPointeeType(); Stack.push_back(Pointer); } else if (isa(Ty)) { T = cast(Ty)->getPointeeType(); Stack.push_back(BlockPointer); } else if (isa(Ty)) { T = cast(Ty)->getPointeeType(); Stack.push_back(MemberPointer); } else if (isa(Ty)) { T = cast(Ty)->getPointeeType(); Stack.push_back(Reference); } else { const Type *DTy = Ty->getUnqualifiedDesugaredType(); if (Ty == DTy) { Fn = 0; return; } T = QualType(DTy, 0); Stack.push_back(Desugar); } } } bool isFunctionType() const { return (Fn != 0); } const FunctionType *get() const { return Fn; } QualType wrap(Sema &S, const FunctionType *New) { // If T wasn't modified from the unwrapped type, do nothing. if (New == get()) return Original; Fn = New; return wrap(S.Context, Original, 0); } private: QualType wrap(ASTContext &C, QualType Old, unsigned I) { if (I == Stack.size()) return C.getQualifiedType(Fn, Old.getQualifiers()); // Build up the inner type, applying the qualifiers from the old // type to the new type. SplitQualType SplitOld = Old.split(); // As a special case, tail-recurse if there are no qualifiers. if (SplitOld.Quals.empty()) return wrap(C, SplitOld.Ty, I); return C.getQualifiedType(wrap(C, SplitOld.Ty, I), SplitOld.Quals); } QualType wrap(ASTContext &C, const Type *Old, unsigned I) { if (I == Stack.size()) return QualType(Fn, 0); switch (static_cast(Stack[I++])) { case Desugar: // This is the point at which we potentially lose source // information. return wrap(C, Old->getUnqualifiedDesugaredType(), I); case Parens: { QualType New = wrap(C, cast(Old)->getInnerType(), I); return C.getParenType(New); } case Pointer: { QualType New = wrap(C, cast(Old)->getPointeeType(), I); return C.getPointerType(New); } case BlockPointer: { QualType New = wrap(C, cast(Old)->getPointeeType(),I); return C.getBlockPointerType(New); } case MemberPointer: { const MemberPointerType *OldMPT = cast(Old); QualType New = wrap(C, OldMPT->getPointeeType(), I); return C.getMemberPointerType(New, OldMPT->getClass()); } case Reference: { const ReferenceType *OldRef = cast(Old); QualType New = wrap(C, OldRef->getPointeeType(), I); if (isa(OldRef)) return C.getLValueReferenceType(New, OldRef->isSpelledAsLValue()); else return C.getRValueReferenceType(New); } } llvm_unreachable("unknown wrapping kind"); } }; } /// Process an individual function attribute. Returns true to /// indicate that the attribute was handled, false if it wasn't. static bool handleFunctionTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type) { Sema &S = state.getSema(); FunctionTypeUnwrapper unwrapped(S, type); if (attr.getKind() == AttributeList::AT_noreturn) { if (S.CheckNoReturnAttr(attr)) return true; // Delay if this is not a function type. if (!unwrapped.isFunctionType()) return false; // Otherwise we can process right away. FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withNoReturn(true); type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); return true; } // ns_returns_retained is not always a type attribute, but if we got // here, we're treating it as one right now. if (attr.getKind() == AttributeList::AT_ns_returns_retained) { assert(S.getLangOpts().ObjCAutoRefCount && "ns_returns_retained treated as type attribute in non-ARC"); if (attr.getNumArgs()) return true; // Delay if this is not a function type. if (!unwrapped.isFunctionType()) return false; FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withProducesResult(true); type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); return true; } if (attr.getKind() == AttributeList::AT_regparm) { unsigned value; if (S.CheckRegparmAttr(attr, value)) return true; // Delay if this is not a function type. if (!unwrapped.isFunctionType()) return false; // Diagnose regparm with fastcall. const FunctionType *fn = unwrapped.get(); CallingConv CC = fn->getCallConv(); if (CC == CC_X86FastCall) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << FunctionType::getNameForCallConv(CC) << "regparm"; attr.setInvalid(); return true; } FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withRegParm(value); type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); return true; } // Otherwise, a calling convention. CallingConv CC; if (S.CheckCallingConvAttr(attr, CC)) return true; // Delay if the type didn't work out to a function. if (!unwrapped.isFunctionType()) return false; const FunctionType *fn = unwrapped.get(); CallingConv CCOld = fn->getCallConv(); if (S.Context.getCanonicalCallConv(CC) == S.Context.getCanonicalCallConv(CCOld)) { FunctionType::ExtInfo EI= unwrapped.get()->getExtInfo().withCallingConv(CC); type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); return true; } if (CCOld != (S.LangOpts.MRTD ? CC_X86StdCall : CC_Default)) { // Should we diagnose reapplications of the same convention? S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << FunctionType::getNameForCallConv(CC) << FunctionType::getNameForCallConv(CCOld); attr.setInvalid(); return true; } // Diagnose the use of X86 fastcall on varargs or unprototyped functions. if (CC == CC_X86FastCall) { if (isa(fn)) { S.Diag(attr.getLoc(), diag::err_cconv_knr) << FunctionType::getNameForCallConv(CC); attr.setInvalid(); return true; } const FunctionProtoType *FnP = cast(fn); if (FnP->isVariadic()) { S.Diag(attr.getLoc(), diag::err_cconv_varargs) << FunctionType::getNameForCallConv(CC); attr.setInvalid(); return true; } // Also diagnose fastcall with regparm. if (fn->getHasRegParm()) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << "regparm" << FunctionType::getNameForCallConv(CC); attr.setInvalid(); return true; } } FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC); type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); return true; } /// Handle OpenCL image access qualifiers: read_only, write_only, read_write static void HandleOpenCLImageAccessAttribute(QualType& CurType, const AttributeList &Attr, Sema &S) { // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; Attr.setInvalid(); return; } Expr *sizeExpr = static_cast(Attr.getArg(0)); llvm::APSInt arg(32); if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() || !sizeExpr->isIntegerConstantExpr(arg, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "opencl_image_access" << sizeExpr->getSourceRange(); Attr.setInvalid(); return; } unsigned iarg = static_cast(arg.getZExtValue()); switch (iarg) { case CLIA_read_only: case CLIA_write_only: case CLIA_read_write: // Implemented in a separate patch break; default: // Implemented in a separate patch S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) << sizeExpr->getSourceRange(); Attr.setInvalid(); break; } } /// HandleVectorSizeAttribute - this attribute is only applicable to integral /// and float scalars, although arrays, pointers, and function return values are /// allowed in conjunction with this construct. Aggregates with this attribute /// are invalid, even if they are of the same size as a corresponding scalar. /// The raw attribute should contain precisely 1 argument, the vector size for /// the variable, measured in bytes. If curType and rawAttr are well formed, /// this routine will return a new vector type. static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, Sema &S) { // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; Attr.setInvalid(); return; } Expr *sizeExpr = static_cast(Attr.getArg(0)); llvm::APSInt vecSize(32); if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() || !sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "vector_size" << sizeExpr->getSourceRange(); Attr.setInvalid(); return; } // the base type must be integer or float, and can't already be a vector. if (!CurType->isIntegerType() && !CurType->isRealFloatingType()) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; Attr.setInvalid(); return; } unsigned typeSize = static_cast(S.Context.getTypeSize(CurType)); // vecSize is specified in bytes - convert to bits. unsigned vectorSize = static_cast(vecSize.getZExtValue() * 8); // the vector size needs to be an integral multiple of the type size. if (vectorSize % typeSize) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) << sizeExpr->getSourceRange(); Attr.setInvalid(); return; } if (vectorSize == 0) { S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) << sizeExpr->getSourceRange(); Attr.setInvalid(); return; } // Success! Instantiate the vector type, the number of elements is > 0, and // not required to be a power of 2, unlike GCC. CurType = S.Context.getVectorType(CurType, vectorSize/typeSize, VectorType::GenericVector); } /// \brief Process the OpenCL-like ext_vector_type attribute when it occurs on /// a type. static void HandleExtVectorTypeAttr(QualType &CurType, const AttributeList &Attr, Sema &S) { Expr *sizeExpr; // Special case where the argument is a template id. if (Attr.getParameterName()) { CXXScopeSpec SS; SourceLocation TemplateKWLoc; UnqualifiedId id; id.setIdentifier(Attr.getParameterName(), Attr.getLoc()); ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, TemplateKWLoc, id, false, false); if (Size.isInvalid()) return; sizeExpr = Size.get(); } else { // check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } sizeExpr = Attr.getArg(0); } // Create the vector type. QualType T = S.BuildExtVectorType(CurType, sizeExpr, Attr.getLoc()); if (!T.isNull()) CurType = T; } /// HandleNeonVectorTypeAttr - The "neon_vector_type" and /// "neon_polyvector_type" attributes are used to create vector types that /// are mangled according to ARM's ABI. Otherwise, these types are identical /// to those created with the "vector_size" attribute. Unlike "vector_size" /// the argument to these Neon attributes is the number of vector elements, /// not the vector size in bytes. The vector width and element type must /// match one of the standard Neon vector types. static void HandleNeonVectorTypeAttr(QualType& CurType, const AttributeList &Attr, Sema &S, VectorType::VectorKind VecKind, const char *AttrName) { // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; Attr.setInvalid(); return; } // The number of elements must be an ICE. Expr *numEltsExpr = static_cast(Attr.getArg(0)); llvm::APSInt numEltsInt(32); if (numEltsExpr->isTypeDependent() || numEltsExpr->isValueDependent() || !numEltsExpr->isIntegerConstantExpr(numEltsInt, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << AttrName << numEltsExpr->getSourceRange(); Attr.setInvalid(); return; } // Only certain element types are supported for Neon vectors. const BuiltinType* BTy = CurType->getAs(); if (!BTy || (VecKind == VectorType::NeonPolyVector && BTy->getKind() != BuiltinType::SChar && BTy->getKind() != BuiltinType::Short) || (BTy->getKind() != BuiltinType::SChar && BTy->getKind() != BuiltinType::UChar && BTy->getKind() != BuiltinType::Short && BTy->getKind() != BuiltinType::UShort && BTy->getKind() != BuiltinType::Int && BTy->getKind() != BuiltinType::UInt && BTy->getKind() != BuiltinType::LongLong && BTy->getKind() != BuiltinType::ULongLong && BTy->getKind() != BuiltinType::Float)) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) <(S.Context.getTypeSize(CurType)); unsigned numElts = static_cast(numEltsInt.getZExtValue()); unsigned vecSize = typeSize * numElts; if (vecSize != 64 && vecSize != 128) { S.Diag(Attr.getLoc(), diag::err_attribute_bad_neon_vector_size) << CurType; Attr.setInvalid(); return; } CurType = S.Context.getVectorType(CurType, numElts, VecKind); } static void processTypeAttrs(TypeProcessingState &state, QualType &type, bool isDeclSpec, AttributeList *attrs) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the // type, but others can be present in the type specifiers even though they // apply to the decl. Here we apply type attributes and ignore the rest. AttributeList *next; do { AttributeList &attr = *attrs; next = attr.getNext(); // Skip attributes that were marked to be invalid. if (attr.isInvalid()) continue; // If this is an attribute we can handle, do so now, // otherwise, add it to the FnAttrs list for rechaining. switch (attr.getKind()) { default: break; case AttributeList::AT_may_alias: // FIXME: This attribute needs to actually be handled, but if we ignore // it it breaks large amounts of Linux software. attr.setUsedAsTypeAttr(); break; case AttributeList::AT_address_space: HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; OBJC_POINTER_TYPE_ATTRS_CASELIST: if (!handleObjCPointerTypeAttr(state, attr, type)) distributeObjCPointerTypeAttr(state, attr, type); attr.setUsedAsTypeAttr(); break; case AttributeList::AT_vector_size: HandleVectorSizeAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; case AttributeList::AT_ext_vector_type: if (state.getDeclarator().getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) HandleExtVectorTypeAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; case AttributeList::AT_neon_vector_type: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonVector, "neon_vector_type"); attr.setUsedAsTypeAttr(); break; case AttributeList::AT_neon_polyvector_type: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonPolyVector, "neon_polyvector_type"); attr.setUsedAsTypeAttr(); break; case AttributeList::AT_opencl_image_access: HandleOpenCLImageAccessAttribute(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; case AttributeList::AT_ns_returns_retained: if (!state.getSema().getLangOpts().ObjCAutoRefCount) break; // fallthrough into the function attrs FUNCTION_TYPE_ATTRS_CASELIST: attr.setUsedAsTypeAttr(); // Never process function type attributes as part of the // declaration-specifiers. if (isDeclSpec) distributeFunctionTypeAttrFromDeclSpec(state, attr, type); // Otherwise, handle the possible delays. else if (!handleFunctionTypeAttr(state, attr, type)) distributeFunctionTypeAttr(state, attr, type); break; } } while ((attrs = next)); } /// \brief Ensure that the type of the given expression is complete. /// /// This routine checks whether the expression \p E has a complete type. If the /// expression refers to an instantiable construct, that instantiation is /// performed as needed to complete its type. Furthermore /// Sema::RequireCompleteType is called for the expression's type (or in the /// case of a reference type, the referred-to type). /// /// \param E The expression whose type is required to be complete. /// \param PD The partial diagnostic that will be printed out if the type cannot /// be completed. /// /// \returns \c true if the type of \p E is incomplete and diagnosed, \c false /// otherwise. bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD, std::pair Note) { QualType T = E->getType(); // Fast path the case where the type is already complete. if (!T->isIncompleteType()) return false; // Incomplete array types may be completed by the initializer attached to // their definitions. For static data members of class templates we need to // instantiate the definition to get this initializer and complete the type. if (T->isIncompleteArrayType()) { if (DeclRefExpr *DRE = dyn_cast(E->IgnoreParens())) { if (VarDecl *Var = dyn_cast(DRE->getDecl())) { if (Var->isStaticDataMember() && Var->getInstantiatedFromStaticDataMember()) { MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); assert(MSInfo && "Missing member specialization information?"); if (MSInfo->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { // If we don't already have a point of instantiation, this is it. if (MSInfo->getPointOfInstantiation().isInvalid()) { MSInfo->setPointOfInstantiation(E->getLocStart()); // This is a modification of an existing AST node. Notify // listeners. if (ASTMutationListener *L = getASTMutationListener()) L->StaticDataMemberInstantiated(Var); } InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var); // Update the type to the newly instantiated definition's type both // here and within the expression. if (VarDecl *Def = Var->getDefinition()) { DRE->setDecl(Def); T = Def->getType(); DRE->setType(T); E->setType(T); } } // We still go on to try to complete the type independently, as it // may also require instantiations or diagnostics if it remains // incomplete. } } } } // FIXME: Are there other cases which require instantiating something other // than the type to complete the type of an expression? // Look through reference types and complete the referred type. if (const ReferenceType *Ref = T->getAs()) T = Ref->getPointeeType(); return RequireCompleteType(E->getExprLoc(), T, PD, Note); } /// @brief Ensure that the type T is a complete type. /// /// This routine checks whether the type @p T is complete in any /// context where a complete type is required. If @p T is a complete /// type, returns false. If @p T is a class template specialization, /// this routine then attempts to perform class template /// instantiation. If instantiation fails, or if @p T is incomplete /// and cannot be completed, issues the diagnostic @p diag (giving it /// the type @p T) and returns true. /// /// @param Loc The location in the source that the incomplete type /// diagnostic should refer to. /// /// @param T The type that this routine is examining for completeness. /// /// @param PD The partial diagnostic that will be printed out if T is not a /// complete type. /// /// @returns @c true if @p T is incomplete and a diagnostic was emitted, /// @c false otherwise. bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD, std::pair Note) { unsigned diag = PD.getDiagID(); // FIXME: Add this assertion to make sure we always get instantiation points. // assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType"); // FIXME: Add this assertion to help us flush out problems with // checking for dependent types and type-dependent expressions. // // assert(!T->isDependentType() && // "Can't ask whether a dependent type is complete"); // If we have a complete type, we're done. NamedDecl *Def = 0; if (!T->isIncompleteType(&Def)) { // If we know about the definition but it is not visible, complain. if (diag != 0 && Def && !LookupResult::isVisible(Def)) { // Suppress this error outside of a SFINAE context if we've already // emitted the error once for this type. There's no usefulness in // repeating the diagnostic. // FIXME: Add a Fix-It that imports the corresponding module or includes // the header. if (isSFINAEContext() || HiddenDefinitions.insert(Def)) { Diag(Loc, diag::err_module_private_definition) << T; Diag(Def->getLocation(), diag::note_previous_definition); } } return false; } const TagType *Tag = T->getAs(); const ObjCInterfaceType *IFace = 0; if (Tag) { // Avoid diagnosing invalid decls as incomplete. if (Tag->getDecl()->isInvalidDecl()) return true; // Give the external AST source a chance to complete the type. if (Tag->getDecl()->hasExternalLexicalStorage()) { Context.getExternalSource()->CompleteType(Tag->getDecl()); if (!Tag->isIncompleteType()) return false; } } else if ((IFace = T->getAs())) { // Avoid diagnosing invalid decls as incomplete. if (IFace->getDecl()->isInvalidDecl()) return true; // Give the external AST source a chance to complete the type. if (IFace->getDecl()->hasExternalLexicalStorage()) { Context.getExternalSource()->CompleteType(IFace->getDecl()); if (!IFace->isIncompleteType()) return false; } } // If we have a class template specialization or a class member of a // class template specialization, or an array with known size of such, // try to instantiate it. QualType MaybeTemplate = T; - if (const ConstantArrayType *Array = Context.getAsConstantArrayType(T)) + while (const ConstantArrayType *Array + = Context.getAsConstantArrayType(MaybeTemplate)) MaybeTemplate = Array->getElementType(); if (const RecordType *Record = MaybeTemplate->getAs()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast(Record->getDecl())) { if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) return InstantiateClassTemplateSpecialization(Loc, ClassTemplateSpec, TSK_ImplicitInstantiation, /*Complain=*/diag != 0); } else if (CXXRecordDecl *Rec = dyn_cast(Record->getDecl())) { CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass(); if (!Rec->isBeingDefined() && Pattern) { MemberSpecializationInfo *MSI = Rec->getMemberSpecializationInfo(); assert(MSI && "Missing member specialization information?"); // This record was instantiated from a class within a template. if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) return InstantiateClass(Loc, Rec, Pattern, getTemplateInstantiationArgs(Rec), TSK_ImplicitInstantiation, /*Complain=*/diag != 0); } } } if (diag == 0) return true; // We have an incomplete type. Produce a diagnostic. Diag(Loc, PD) << T; // If we have a note, produce it. if (!Note.first.isInvalid()) Diag(Note.first, Note.second); // If the type was a forward declaration of a class/struct/union // type, produce a note. if (Tag && !Tag->getDecl()->isInvalidDecl()) Diag(Tag->getDecl()->getLocation(), Tag->isBeingDefined() ? diag::note_type_being_defined : diag::note_forward_declaration) << QualType(Tag, 0); // If the Objective-C class was a forward declaration, produce a note. if (IFace && !IFace->getDecl()->isInvalidDecl()) Diag(IFace->getDecl()->getLocation(), diag::note_forward_class); return true; } bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD) { return RequireCompleteType(Loc, T, PD, std::make_pair(SourceLocation(), PDiag(0))); } bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID) { return RequireCompleteType(Loc, T, PDiag(DiagID), std::make_pair(SourceLocation(), PDiag(0))); } /// @brief Ensure that the type T is a literal type. /// /// This routine checks whether the type @p T is a literal type. If @p T is an /// incomplete type, an attempt is made to complete it. If @p T is a literal /// type, or @p AllowIncompleteType is true and @p T is an incomplete type, /// returns false. Otherwise, this routine issues the diagnostic @p PD (giving /// it the type @p T), along with notes explaining why the type is not a /// literal type, and returns true. /// /// @param Loc The location in the source that the non-literal type /// diagnostic should refer to. /// /// @param T The type that this routine is examining for literalness. /// /// @param PD The partial diagnostic that will be printed out if T is not a /// literal type. /// /// @returns @c true if @p T is not a literal type and a diagnostic was emitted, /// @c false otherwise. bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD) { assert(!T->isDependentType() && "type should not be dependent"); QualType ElemType = Context.getBaseElementType(T); RequireCompleteType(Loc, ElemType, 0); if (T->isLiteralType()) return false; if (PD.getDiagID() == 0) return true; Diag(Loc, PD) << T; if (T->isVariableArrayType()) return true; const RecordType *RT = ElemType->getAs(); if (!RT) return true; const CXXRecordDecl *RD = cast(RT->getDecl()); // FIXME: Better diagnostic for incomplete class? if (!RD->isCompleteDefinition()) return true; // If the class has virtual base classes, then it's not an aggregate, and // cannot have any constexpr constructors or a trivial default constructor, // so is non-literal. This is better to diagnose than the resulting absence // of constexpr constructors. if (RD->getNumVBases()) { Diag(RD->getLocation(), diag::note_non_literal_virtual_base) << RD->isStruct() << RD->getNumVBases(); for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) Diag(I->getLocStart(), diag::note_constexpr_virtual_base_here) << I->getSourceRange(); } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor() && !RD->hasTrivialDefaultConstructor()) { Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD; } else if (RD->hasNonLiteralTypeFieldsOrBases()) { for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { if (!I->getType()->isLiteralType()) { Diag(I->getLocStart(), diag::note_non_literal_base_class) << RD << I->getType() << I->getSourceRange(); return true; } } for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) { if (!(*I)->getType()->isLiteralType() || (*I)->getType().isVolatileQualified()) { Diag((*I)->getLocation(), diag::note_non_literal_field) << RD << (*I) << (*I)->getType() << (*I)->getType().isVolatileQualified(); return true; } } } else if (!RD->hasTrivialDestructor()) { // All fields and bases are of literal types, so have trivial destructors. // If this class's destructor is non-trivial it must be user-declared. CXXDestructorDecl *Dtor = RD->getDestructor(); assert(Dtor && "class has literal fields and bases but no dtor?"); if (!Dtor) return true; Diag(Dtor->getLocation(), Dtor->isUserProvided() ? diag::note_non_literal_user_provided_dtor : diag::note_non_literal_nontrivial_dtor) << RD; } return true; } /// \brief Retrieve a version of the type 'T' that is elaborated by Keyword /// and qualified by the nested-name-specifier contained in SS. QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, const CXXScopeSpec &SS, QualType T) { if (T.isNull()) return T; NestedNameSpecifier *NNS; if (SS.isValid()) NNS = static_cast(SS.getScopeRep()); else { if (Keyword == ETK_None) return T; NNS = 0; } return Context.getElaboratedType(Keyword, NNS, T); } QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { ExprResult ER = CheckPlaceholderExpr(E); if (ER.isInvalid()) return QualType(); E = ER.take(); if (!E->isTypeDependent()) { QualType T = E->getType(); if (const TagType *TT = T->getAs()) DiagnoseUseOfDecl(TT->getDecl(), E->getExprLoc()); } return Context.getTypeOfExprType(E); } /// getDecltypeForExpr - Given an expr, will return the decltype for /// that expression, according to the rules in C++11 /// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18. static QualType getDecltypeForExpr(Sema &S, Expr *E) { if (E->isTypeDependent()) return S.Context.DependentTy; // C++11 [dcl.type.simple]p4: // The type denoted by decltype(e) is defined as follows: // // - if e is an unparenthesized id-expression or an unparenthesized class // member access (5.2.5), decltype(e) is the type of the entity named // by e. If there is no such entity, or if e names a set of overloaded // functions, the program is ill-formed; if (const DeclRefExpr *DRE = dyn_cast(E)) { if (const ValueDecl *VD = dyn_cast(DRE->getDecl())) return VD->getType(); } if (const MemberExpr *ME = dyn_cast(E)) { if (const FieldDecl *FD = dyn_cast(ME->getMemberDecl())) return FD->getType(); } // C++11 [expr.lambda.prim]p18: // Every occurrence of decltype((x)) where x is a possibly // parenthesized id-expression that names an entity of automatic // storage duration is treated as if x were transformed into an // access to a corresponding data member of the closure type that // would have been declared if x were an odr-use of the denoted // entity. using namespace sema; if (S.getCurLambda()) { if (isa(E)) { if (DeclRefExpr *DRE = dyn_cast(E->IgnoreParens())) { if (VarDecl *Var = dyn_cast(DRE->getDecl())) { QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation()); if (!T.isNull()) return S.Context.getLValueReferenceType(T); } } } } // C++11 [dcl.type.simple]p4: // [...] QualType T = E->getType(); switch (E->getValueKind()) { // - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the // type of e; case VK_XValue: T = S.Context.getRValueReferenceType(T); break; // - otherwise, if e is an lvalue, decltype(e) is T&, where T is the // type of e; case VK_LValue: T = S.Context.getLValueReferenceType(T); break; // - otherwise, decltype(e) is the type of e. case VK_RValue: break; } return T; } QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { ExprResult ER = CheckPlaceholderExpr(E); if (ER.isInvalid()) return QualType(); E = ER.take(); return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); } QualType Sema::BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc) { switch (UKind) { case UnaryTransformType::EnumUnderlyingType: if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) { Diag(Loc, diag::err_only_enums_have_underlying_types); return QualType(); } else { QualType Underlying = BaseType; if (!BaseType->isDependentType()) { EnumDecl *ED = BaseType->getAs()->getDecl(); assert(ED && "EnumType has no EnumDecl"); DiagnoseUseOfDecl(ED, Loc); Underlying = ED->getIntegerType(); } assert(!Underlying.isNull()); return Context.getUnaryTransformType(BaseType, Underlying, UnaryTransformType::EnumUnderlyingType); } } llvm_unreachable("unknown unary transform type"); } QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { if (!T->isDependentType()) { // FIXME: It isn't entirely clear whether incomplete atomic types // are allowed or not; for simplicity, ban them for the moment. if (RequireCompleteType(Loc, T, PDiag(diag::err_atomic_specifier_bad_type) << 0)) return QualType(); int DisallowedKind = -1; if (T->isArrayType()) DisallowedKind = 1; else if (T->isFunctionType()) DisallowedKind = 2; else if (T->isReferenceType()) DisallowedKind = 3; else if (T->isAtomicType()) DisallowedKind = 4; else if (T.hasQualifiers()) DisallowedKind = 5; else if (!T.isTriviallyCopyableType(Context)) // Some other non-trivially-copyable type (probably a C++ class) DisallowedKind = 6; if (DisallowedKind != -1) { Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T; return QualType(); } // FIXME: Do we need any handling for ARC here? } // Build the pointer type. return Context.getAtomicType(T); } Index: vendor/clang/dist/lib/Serialization/ASTReader.cpp =================================================================== --- vendor/clang/dist/lib/Serialization/ASTReader.cpp (revision 235808) +++ vendor/clang/dist/lib/Serialization/ASTReader.cpp (revision 235809) @@ -1,6377 +1,6380 @@ //===--- ASTReader.cpp - AST File Reader ------------------------*- 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 ASTReader class, which reads AST files. // //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "clang/Serialization/ModuleManager.h" #include "clang/Serialization/SerializationDiagnostic.h" #include "ASTCommon.h" #include "ASTReaderInternals.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Scope.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Basic/OnDiskHashTable.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/Basic/VersionTuple.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/system_error.h" #include #include #include #include using namespace clang; using namespace clang::serialization; using namespace clang::serialization::reader; //===----------------------------------------------------------------------===// // PCH validator implementation //===----------------------------------------------------------------------===// ASTReaderListener::~ASTReaderListener() {} bool PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { const LangOptions &PPLangOpts = PP.getLangOpts(); #define LANGOPT(Name, Bits, Default, Description) \ if (PPLangOpts.Name != LangOpts.Name) { \ Reader.Diag(diag::err_pch_langopt_mismatch) \ << Description << LangOpts.Name << PPLangOpts.Name; \ return true; \ } #define VALUE_LANGOPT(Name, Bits, Default, Description) \ if (PPLangOpts.Name != LangOpts.Name) { \ Reader.Diag(diag::err_pch_langopt_value_mismatch) \ << Description; \ return true; \ } #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ if (PPLangOpts.get##Name() != LangOpts.get##Name()) { \ Reader.Diag(diag::err_pch_langopt_value_mismatch) \ << Description; \ return true; \ } #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" return false; } bool PCHValidator::ReadTargetTriple(StringRef Triple) { if (Triple == PP.getTargetInfo().getTriple().str()) return false; Reader.Diag(diag::warn_pch_target_triple) << Triple << PP.getTargetInfo().getTriple().str(); return true; } namespace { struct EmptyStringRef { bool operator ()(StringRef r) const { return r.empty(); } }; struct EmptyBlock { bool operator ()(const PCHPredefinesBlock &r) const {return r.Data.empty();} }; } static bool EqualConcatenations(SmallVector L, PCHPredefinesBlocks R) { // First, sum up the lengths. unsigned LL = 0, RL = 0; for (unsigned I = 0, N = L.size(); I != N; ++I) { LL += L[I].size(); } for (unsigned I = 0, N = R.size(); I != N; ++I) { RL += R[I].Data.size(); } if (LL != RL) return false; if (LL == 0 && RL == 0) return true; // Kick out empty parts, they confuse the algorithm below. L.erase(std::remove_if(L.begin(), L.end(), EmptyStringRef()), L.end()); R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end()); // Do it the hard way. At this point, both vectors must be non-empty. StringRef LR = L[0], RR = R[0].Data; unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size(); (void) RN; for (;;) { // Compare the current pieces. if (LR.size() == RR.size()) { // If they're the same length, it's pretty easy. if (LR != RR) return false; // Both pieces are done, advance. ++LI; ++RI; // If either string is done, they're both done, since they're the same // length. if (LI == LN) { assert(RI == RN && "Strings not the same length after all?"); return true; } LR = L[LI]; RR = R[RI].Data; } else if (LR.size() < RR.size()) { // Right piece is longer. if (!RR.startswith(LR)) return false; ++LI; assert(LI != LN && "Strings not the same length after all?"); RR = RR.substr(LR.size()); LR = L[LI]; } else { // Left piece is longer. if (!LR.startswith(RR)) return false; ++RI; assert(RI != RN && "Strings not the same length after all?"); LR = LR.substr(RR.size()); RR = R[RI].Data; } } } static std::pair FindMacro(const PCHPredefinesBlocks &Buffers, StringRef MacroDef) { std::pair Res; for (unsigned I = 0, N = Buffers.size(); I != N; ++I) { Res.second = Buffers[I].Data.find(MacroDef); if (Res.second != StringRef::npos) { Res.first = Buffers[I].BufferID; break; } } return Res; } bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, StringRef OriginalFileName, std::string &SuggestedPredefines, FileManager &FileMgr) { // We are in the context of an implicit include, so the predefines buffer will // have a #include entry for the PCH file itself (as normalized by the // preprocessor initialization). Find it and skip over it in the checking // below. SmallString<256> PCHInclude; PCHInclude += "#include \""; PCHInclude += HeaderSearch::NormalizeDashIncludePath(OriginalFileName, FileMgr); PCHInclude += "\"\n"; std::pair Split = StringRef(PP.getPredefines()).split(PCHInclude.str()); StringRef Left = Split.first, Right = Split.second; if (Left == PP.getPredefines()) { Error("Missing PCH include entry!"); return true; } // If the concatenation of all the PCH buffers is equal to the adjusted // command line, we're done. SmallVector CommandLine; CommandLine.push_back(Left); CommandLine.push_back(Right); if (EqualConcatenations(CommandLine, Buffers)) return false; SourceManager &SourceMgr = PP.getSourceManager(); // The predefines buffers are different. Determine what the differences are, // and whether they require us to reject the PCH file. SmallVector PCHLines; for (unsigned I = 0, N = Buffers.size(); I != N; ++I) Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); SmallVector CmdLineLines; Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); // Pick out implicit #includes after the PCH and don't consider them for // validation; we will insert them into SuggestedPredefines so that the // preprocessor includes them. std::string IncludesAfterPCH; SmallVector AfterPCHLines; Right.split(AfterPCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); for (unsigned i = 0, e = AfterPCHLines.size(); i != e; ++i) { if (AfterPCHLines[i].startswith("#include ")) { IncludesAfterPCH += AfterPCHLines[i]; IncludesAfterPCH += '\n'; } else { CmdLineLines.push_back(AfterPCHLines[i]); } } // Make sure we add the includes last into SuggestedPredefines before we // exit this function. struct AddIncludesRAII { std::string &SuggestedPredefines; std::string &IncludesAfterPCH; AddIncludesRAII(std::string &SuggestedPredefines, std::string &IncludesAfterPCH) : SuggestedPredefines(SuggestedPredefines), IncludesAfterPCH(IncludesAfterPCH) { } ~AddIncludesRAII() { SuggestedPredefines += IncludesAfterPCH; } } AddIncludes(SuggestedPredefines, IncludesAfterPCH); // Sort both sets of predefined buffer lines, since we allow some extra // definitions and they may appear at any point in the output. std::sort(CmdLineLines.begin(), CmdLineLines.end()); std::sort(PCHLines.begin(), PCHLines.end()); // Determine which predefines that were used to build the PCH file are missing // from the command line. std::vector MissingPredefines; std::set_difference(PCHLines.begin(), PCHLines.end(), CmdLineLines.begin(), CmdLineLines.end(), std::back_inserter(MissingPredefines)); bool MissingDefines = false; bool ConflictingDefines = false; for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) { StringRef Missing = MissingPredefines[I]; if (Missing.startswith("#include ")) { // An -include was specified when generating the PCH; it is included in // the PCH, just ignore it. continue; } if (!Missing.startswith("#define ")) { Reader.Diag(diag::warn_pch_compiler_options_mismatch); return true; } // This is a macro definition. Determine the name of the macro we're // defining. std::string::size_type StartOfMacroName = strlen("#define "); std::string::size_type EndOfMacroName = Missing.find_first_of("( \n\r", StartOfMacroName); assert(EndOfMacroName != std::string::npos && "Couldn't find the end of the macro name"); StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName); // Determine whether this macro was given a different definition on the // command line. std::string MacroDefStart = "#define " + MacroName.str(); std::string::size_type MacroDefLen = MacroDefStart.size(); SmallVector::iterator ConflictPos = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(), MacroDefStart); for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) { if (!ConflictPos->startswith(MacroDefStart)) { // Different macro; we're done. ConflictPos = CmdLineLines.end(); break; } assert(ConflictPos->size() > MacroDefLen && "Invalid #define in predefines buffer?"); if ((*ConflictPos)[MacroDefLen] != ' ' && (*ConflictPos)[MacroDefLen] != '(') continue; // Longer macro name; keep trying. // We found a conflicting macro definition. break; } if (ConflictPos != CmdLineLines.end()) { Reader.Diag(diag::warn_cmdline_conflicting_macro_def) << MacroName; // Show the definition of this macro within the PCH file. std::pair MacroLoc = FindMacro(Buffers, Missing); assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!"); SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(MacroLoc.first) .getLocWithOffset(MacroLoc.second); Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName; ConflictingDefines = true; continue; } // If the macro doesn't conflict, then we'll just pick up the macro // definition from the PCH file. Warn the user that they made a mistake. if (ConflictingDefines) continue; // Don't complain if there are already conflicting defs if (!MissingDefines) { Reader.Diag(diag::warn_cmdline_missing_macro_defs); MissingDefines = true; } // Show the definition of this macro within the PCH file. std::pair MacroLoc = FindMacro(Buffers, Missing); assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!"); SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(MacroLoc.first) .getLocWithOffset(MacroLoc.second); Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); } if (ConflictingDefines) return true; // Determine what predefines were introduced based on command-line // parameters that were not present when building the PCH // file. Extra #defines are okay, so long as the identifiers being // defined were not used within the precompiled header. std::vector ExtraPredefines; std::set_difference(CmdLineLines.begin(), CmdLineLines.end(), PCHLines.begin(), PCHLines.end(), std::back_inserter(ExtraPredefines)); for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) { StringRef &Extra = ExtraPredefines[I]; if (!Extra.startswith("#define ")) { Reader.Diag(diag::warn_pch_compiler_options_mismatch); return true; } // This is an extra macro definition. Determine the name of the // macro we're defining. std::string::size_type StartOfMacroName = strlen("#define "); std::string::size_type EndOfMacroName = Extra.find_first_of("( \n\r", StartOfMacroName); assert(EndOfMacroName != std::string::npos && "Couldn't find the end of the macro name"); StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName); // Check whether this name was used somewhere in the PCH file. If // so, defining it as a macro could change behavior, so we reject // the PCH file. if (IdentifierInfo *II = Reader.get(MacroName)) { Reader.Diag(diag::warn_macro_name_used_in_pch) << II; return true; } // Add this definition to the suggested predefines buffer. SuggestedPredefines += Extra; SuggestedPredefines += '\n'; } // If we get here, it's because the predefines buffer had compatible // contents. Accept the PCH file. return false; } void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) { PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID); ++NumHeaderInfos; } void PCHValidator::ReadCounter(unsigned Value) { PP.setCounterValue(Value); } //===----------------------------------------------------------------------===// // AST reader implementation //===----------------------------------------------------------------------===// void ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) { DeserializationListener = Listener; } unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) { return serialization::ComputeHash(Sel); } std::pair ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) { using namespace clang::io; unsigned KeyLen = ReadUnalignedLE16(d); unsigned DataLen = ReadUnalignedLE16(d); return std::make_pair(KeyLen, DataLen); } ASTSelectorLookupTrait::internal_key_type ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) { using namespace clang::io; SelectorTable &SelTable = Reader.getContext().Selectors; unsigned N = ReadUnalignedLE16(d); IdentifierInfo *FirstII = Reader.getLocalIdentifier(F, ReadUnalignedLE32(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, ReadUnalignedLE32(d))); return SelTable.getSelector(N, Args.data()); } ASTSelectorLookupTrait::data_type ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, unsigned DataLen) { using namespace clang::io; data_type Result; Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d)); unsigned NumInstanceMethods = ReadUnalignedLE16(d); unsigned NumFactoryMethods = ReadUnalignedLE16(d); // Load instance methods for (unsigned I = 0; I != NumInstanceMethods; ++I) { if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d))) Result.Instance.push_back(Method); } // Load factory methods for (unsigned I = 0; I != NumFactoryMethods; ++I) { if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d))) Result.Factory.push_back(Method); } return Result; } unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) { return llvm::HashString(StringRef(a.first, a.second)); } std::pair ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) { using namespace clang::io; unsigned DataLen = ReadUnalignedLE16(d); unsigned KeyLen = ReadUnalignedLE16(d); return std::make_pair(KeyLen, DataLen); } std::pair ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) { assert(n >= 2 && d[n-1] == '\0'); return std::make_pair((const char*) d, n-1); } IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, const unsigned char* d, unsigned DataLen) { using namespace clang::io; unsigned RawID = ReadUnalignedLE32(d); bool IsInteresting = RawID & 0x01; // Wipe out the "is interesting" bit. RawID = RawID >> 1; IdentID ID = Reader.getGlobalIdentifierID(F, RawID); if (!IsInteresting) { // For uninteresting identifiers, just build the IdentifierInfo // and associate it with the persistent ID. IdentifierInfo *II = KnownII; if (!II) { II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); KnownII = II; } Reader.SetIdentifierInfo(ID, II); II->setIsFromAST(); Reader.markIdentifierUpToDate(II); return II; } unsigned Bits = ReadUnalignedLE16(d); bool CPlusPlusOperatorKeyword = Bits & 0x01; Bits >>= 1; bool HasRevertedTokenIDToIdentifier = Bits & 0x01; Bits >>= 1; bool Poisoned = Bits & 0x01; Bits >>= 1; bool ExtensionToken = Bits & 0x01; Bits >>= 1; bool hasMacroDefinition = Bits & 0x01; Bits >>= 1; unsigned ObjCOrBuiltinID = Bits & 0x7FF; Bits >>= 11; assert(Bits == 0 && "Extra bits in the identifier?"); DataLen -= 6; // Build the IdentifierInfo itself and link the identifier ID with // the new IdentifierInfo. IdentifierInfo *II = KnownII; if (!II) { II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); KnownII = II; } Reader.markIdentifierUpToDate(II); II->setIsFromAST(); // Set or check the various bits in the IdentifierInfo structure. // Token IDs are read-only. if (HasRevertedTokenIDToIdentifier) II->RevertTokenIDToIdentifier(); II->setObjCOrBuiltinID(ObjCOrBuiltinID); 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 (hasMacroDefinition) { // FIXME: Check for conflicts? uint32_t Offset = ReadUnalignedLE32(d); unsigned LocalSubmoduleID = ReadUnalignedLE32(d); // Determine whether this macro definition should be visible now, or // whether it is in a hidden submodule. bool Visible = true; if (SubmoduleID GlobalSubmoduleID = Reader.getGlobalSubmoduleID(F, LocalSubmoduleID)) { if (Module *Owner = Reader.getSubmodule(GlobalSubmoduleID)) { if (Owner->NameVisibility == Module::Hidden) { // The owning module is not visible, and this macro definition should // not be, either. Visible = false; // Note that this macro definition was hidden because its owning // module is not yet visible. Reader.HiddenNamesMap[Owner].push_back(II); } } } Reader.setIdentifierIsMacro(II, F, Offset, Visible); DataLen -= 8; } 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, ReadUnalignedLE32(d))); Reader.SetGloballyVisibleDecls(II, DeclIDs); } return II; } unsigned ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const { llvm::FoldingSetNodeID ID; ID.AddInteger(Key.Kind); switch (Key.Kind) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: ID.AddString(((IdentifierInfo*)Key.Data)->getName()); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: ID.AddInteger(serialization::ComputeHash(Selector(Key.Data))); break; case DeclarationName::CXXOperatorName: ID.AddInteger((OverloadedOperatorKind)Key.Data); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: break; } return ID.ComputeHash(); } ASTDeclContextNameLookupTrait::internal_key_type ASTDeclContextNameLookupTrait::GetInternalKey( const external_key_type& Name) const { DeclNameKey Key; Key.Kind = Name.getNameKind(); switch (Name.getNameKind()) { case DeclarationName::Identifier: Key.Data = (uint64_t)Name.getAsIdentifierInfo(); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); break; case DeclarationName::CXXOperatorName: Key.Data = Name.getCXXOverloadedOperator(); break; case DeclarationName::CXXLiteralOperatorName: Key.Data = (uint64_t)Name.getCXXLiteralIdentifier(); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: Key.Data = 0; break; } return Key; } std::pair ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) { using namespace clang::io; unsigned KeyLen = ReadUnalignedLE16(d); unsigned DataLen = ReadUnalignedLE16(d); return std::make_pair(KeyLen, DataLen); } ASTDeclContextNameLookupTrait::internal_key_type ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) { using namespace clang::io; DeclNameKey Key; Key.Kind = (DeclarationName::NameKind)*d++; switch (Key.Kind) { case DeclarationName::Identifier: Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: Key.Data = (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d)) .getAsOpaquePtr(); break; case DeclarationName::CXXOperatorName: Key.Data = *d++; // OverloadedOperatorKind break; case DeclarationName::CXXLiteralOperatorName: Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: Key.Data = 0; break; } return Key; } ASTDeclContextNameLookupTrait::data_type ASTDeclContextNameLookupTrait::ReadData(internal_key_type, const unsigned char* d, unsigned DataLen) { using namespace clang::io; unsigned NumDecls = ReadUnalignedLE16(d); LE32DeclID *Start = (LE32DeclID *)d; return std::make_pair(Start, Start + NumDecls); } bool ASTReader::ReadDeclContextStorage(ModuleFile &M, llvm::BitstreamCursor &Cursor, const std::pair &Offsets, DeclContextInfo &Info) { SavedStreamPosition SavedPosition(Cursor); // First the lexical decls. if (Offsets.first != 0) { Cursor.JumpToBit(Offsets.first); RecordData Record; const char *Blob; unsigned BlobLen; unsigned Code = Cursor.ReadCode(); unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen); if (RecCode != DECL_CONTEXT_LEXICAL) { Error("Expected lexical block"); return true; } Info.LexicalDecls = reinterpret_cast(Blob); Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair); } // Now the lookup table. if (Offsets.second != 0) { Cursor.JumpToBit(Offsets.second); RecordData Record; const char *Blob; unsigned BlobLen; unsigned Code = Cursor.ReadCode(); unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen); if (RecCode != DECL_CONTEXT_VISIBLE) { Error("Expected visible lookup table block"); return true; } Info.NameLookupTableData = ASTDeclContextNameLookupTable::Create( (const unsigned char *)Blob + Record[0], (const unsigned char *)Blob, ASTDeclContextNameLookupTrait(*this, M)); } return false; } void ASTReader::Error(StringRef Msg) { Error(diag::err_fe_pch_malformed, Msg); } void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2) { if (Diags.isDiagnosticInFlight()) Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2); else Diag(DiagID) << Arg1 << Arg2; } /// \brief Tell the AST listener about the predefines buffers in the chain. bool ASTReader::CheckPredefinesBuffers() { if (Listener) return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers, ActualOriginalFileName, SuggestedPredefines, FileMgr); return false; } //===----------------------------------------------------------------------===// // 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, SmallVectorImpl &Record) { unsigned Idx = 0; LineTableInfo &LineTable = SourceMgr.getLineTable(); // Parse the file names std::map FileIDs; for (int I = 0, N = Record[Idx++]; I != N; ++I) { // Extract the file name unsigned FilenameLen = Record[Idx++]; std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen); Idx += FilenameLen; MaybeAddSystemRootToFilename(Filename); FileIDs[I] = LineTable.getLineTableFilenameID(Filename); } // 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 && "Numentries is 00000"); 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(FID, Entries); } return false; } namespace { class ASTStatData { public: const ino_t ino; const dev_t dev; const mode_t mode; const time_t mtime; const off_t size; ASTStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s) : ino(i), dev(d), mode(mo), mtime(m), size(s) {} }; class ASTStatLookupTrait { public: typedef const char *external_key_type; typedef const char *internal_key_type; typedef ASTStatData data_type; static unsigned ComputeHash(const char *path) { return llvm::HashString(path); } static internal_key_type GetInternalKey(const char *path) { return path; } static bool EqualKey(internal_key_type a, internal_key_type b) { return strcmp(a, b) == 0; } static std::pair ReadKeyDataLength(const unsigned char*& d) { unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); unsigned DataLen = (unsigned) *d++; return std::make_pair(KeyLen + 1, DataLen); } static internal_key_type ReadKey(const unsigned char *d, unsigned) { return (const char *)d; } static data_type ReadData(const internal_key_type, const unsigned char *d, unsigned /*DataLen*/) { using namespace clang::io; ino_t ino = (ino_t) ReadUnalignedLE32(d); dev_t dev = (dev_t) ReadUnalignedLE32(d); mode_t mode = (mode_t) ReadUnalignedLE16(d); time_t mtime = (time_t) ReadUnalignedLE64(d); off_t size = (off_t) ReadUnalignedLE64(d); return data_type(ino, dev, mode, mtime, size); } }; /// \brief stat() cache for precompiled headers. /// /// This cache is very similar to the stat cache used by pretokenized /// headers. class ASTStatCache : public FileSystemStatCache { typedef OnDiskChainedHashTable CacheTy; CacheTy *Cache; unsigned &NumStatHits, &NumStatMisses; public: ASTStatCache(const unsigned char *Buckets, const unsigned char *Base, unsigned &NumStatHits, unsigned &NumStatMisses) : Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) { Cache = CacheTy::Create(Buckets, Base); } ~ASTStatCache() { delete Cache; } LookupResult getStat(const char *Path, struct stat &StatBuf, int *FileDescriptor) { // Do the lookup for the file's data in the AST file. CacheTy::iterator I = Cache->find(Path); // If we don't get a hit in the AST file just forward to 'stat'. if (I == Cache->end()) { ++NumStatMisses; return statChained(Path, StatBuf, FileDescriptor); } ++NumStatHits; ASTStatData Data = *I; StatBuf.st_ino = Data.ino; StatBuf.st_dev = Data.dev; StatBuf.st_mtime = Data.mtime; StatBuf.st_mode = Data.mode; StatBuf.st_size = Data.size; return CacheExists; } }; } // end anonymous namespace /// \brief Read a source manager block ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) { using namespace SrcMgr; llvm::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 Failure; } // Enter the source manager block. if (SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) { Error("malformed source manager block record in AST file"); return Failure; } RecordData Record; while (true) { unsigned Code = SLocEntryCursor.ReadCode(); if (Code == llvm::bitc::END_BLOCK) { if (SLocEntryCursor.ReadBlockEnd()) { Error("error at end of Source Manager block in AST file"); return Failure; } return Success; } if (Code == llvm::bitc::ENTER_SUBBLOCK) { // No known subblocks, always skip them. SLocEntryCursor.ReadSubBlockID(); if (SLocEntryCursor.SkipBlock()) { Error("malformed block record in AST file"); return Failure; } continue; } if (Code == llvm::bitc::DEFINE_ABBREV) { SLocEntryCursor.ReadAbbrevRecord(); continue; } // Read a record. const char *BlobStart; unsigned BlobLen; Record.clear(); switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { 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 Success; } } } /// \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(); } /// \brief Read in the source location entry with the given ID. ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { if (ID == 0) return Success; if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { Error("source location entry ID out-of-range for AST file"); return Failure; } ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second; F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]); llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; unsigned BaseOffset = F->SLocEntryBaseOffset; ++NumSLocEntriesRead; unsigned Code = SLocEntryCursor.ReadCode(); if (Code == llvm::bitc::END_BLOCK || Code == llvm::bitc::ENTER_SUBBLOCK || Code == llvm::bitc::DEFINE_ABBREV) { Error("incorrectly-formatted source location entry in AST file"); return Failure; } RecordData Record; const char *BlobStart; unsigned BlobLen; switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { default: Error("incorrectly-formatted source location entry in AST file"); return Failure; case SM_SLOC_FILE_ENTRY: { if (Record.size() < 7) { Error("source location entry is incorrect"); return Failure; } // 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. ASTReader::ASTReadResult Result = Success; bool OverriddenBuffer = Record[6]; std::string OrigFilename(BlobStart, BlobStart + BlobLen); std::string Filename = OrigFilename; MaybeAddSystemRootToFilename(Filename); const FileEntry *File = OverriddenBuffer? FileMgr.getVirtualFile(Filename, (off_t)Record[4], (time_t)Record[5]) : FileMgr.getFile(Filename, /*OpenFile=*/false); if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() && OriginalDir != CurrentDir) { std::string resolved = resolveFileRelativeToOriginalDir(Filename, OriginalDir, CurrentDir); if (!resolved.empty()) File = FileMgr.getFile(resolved); } if (File == 0) File = FileMgr.getVirtualFile(Filename, (off_t)Record[4], (time_t)Record[5]); if (File == 0) { std::string ErrorStr = "could not find file '"; ErrorStr += Filename; ErrorStr += "' referenced by AST file"; Error(ErrorStr.c_str()); return Failure; } if (!DisableValidation && ((off_t)Record[4] != File->getSize() #if !defined(LLVM_ON_WIN32) // In our regression testing, the Windows file system seems to // have inconsistent modification times that sometimes // erroneously trigger this error-handling path. || (time_t)Record[5] != File->getModificationTime() #endif )) { Error(diag::err_fe_pch_file_modified, Filename); Result = Failure; } SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) { // This is the module's main file. IncludeLoc = getImportLocation(F); } FileID FID = SourceMgr.createFileID(File, IncludeLoc, (SrcMgr::CharacteristicKind)Record[2], ID, BaseOffset + Record[0]); SrcMgr::FileInfo &FileInfo = const_cast(SourceMgr.getSLocEntry(FID).getFile()); FileInfo.NumCreatedFIDs = Record[7]; if (Record[3]) FileInfo.setHasLineDirectives(); const DeclID *FirstDecl = F->FileSortedDecls + Record[8]; unsigned NumFileDecls = Record[9]; 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); if (OverriddenBuffer && !ContentCache->BufferOverridden && ContentCache->ContentsEntry == ContentCache->OrigEntry) { unsigned Code = SLocEntryCursor.ReadCode(); Record.clear(); unsigned RecCode = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); if (RecCode != SM_SLOC_BUFFER_BLOB) { Error("AST record has invalid code"); return Failure; } llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), Filename); SourceMgr.overrideFileContents(File, Buffer); } if (Result == Failure) return Failure; break; } case SM_SLOC_BUFFER_ENTRY: { const char *Name = BlobStart; unsigned Offset = Record[0]; unsigned Code = SLocEntryCursor.ReadCode(); Record.clear(); unsigned RecCode = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); if (RecCode != SM_SLOC_BUFFER_BLOB) { Error("AST record has invalid code"); return Failure; } llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), Name); FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, BaseOffset + Offset); if (strcmp(Name, "") == 0 && F->Kind == MK_PCH) { PCHPredefinesBlock Block = { BufferID, StringRef(BlobStart, BlobLen - 1) }; PCHPredefinesBuffers.push_back(Block); } 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 Success; } /// \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. We assume that it is the first entry in the // entry table. We can't ask the manager, because at the time of PCH loading // the main file entry doesn't exist yet. // The very first entry is the invalid instantiation loc, which takes up // offsets 0 and 1. return SourceLocation::getFromRawEncoding(2U); } //return F->Loaders[0]->FirstLoc; 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(llvm::BitstreamCursor &Cursor, unsigned BlockID) { if (Cursor.EnterSubBlock(BlockID)) { Error("malformed block record in AST file"); return Failure; } 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(); } } void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { llvm::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 = 0; while (true) { unsigned Code = Stream.ReadCode(); switch (Code) { case llvm::bitc::END_BLOCK: return; case llvm::bitc::ENTER_SUBBLOCK: // No known subblocks, always skip them. Stream.ReadSubBlockID(); if (Stream.SkipBlock()) { Error("malformed block record in AST file"); return; } continue; case llvm::bitc::DEFINE_ABBREV: Stream.ReadAbbrevRecord(); continue; default: break; } // Read a record. const char *BlobStart = 0; unsigned BlobLen = 0; Record.clear(); PreprocessorRecordTypes RecType = (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart, BlobLen); switch (RecType) { 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; IdentifierInfo *II = getLocalIdentifier(F, Record[0]); if (II == 0) { Error("macro must have a name in AST file"); return; } SourceLocation Loc = ReadSourceLocation(F, Record[1]); bool isUsed = Record[2]; MacroInfo *MI = PP.AllocateMacroInfo(Loc); MI->setIsUsed(isUsed); MI->setIsFromAST(); bool IsPublic = Record[3]; unsigned NextIndex = 4; MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex)); if (RecType == PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. bool isC99VarArgs = Record[NextIndex++]; bool isGNUVarArgs = 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(); MI->setArgumentList(MacroArgs.data(), MacroArgs.size(), PP.getPreprocessorAllocator()); } // Finally, install the macro. PP.setMacroInfo(II, MI, /*LoadedFromAST=*/true); // 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(); PPRec.RegisterMacroDefinition(Macro, PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true)); } ++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 == 0) break; Token Tok; Tok.startToken(); Tok.setLocation(ReadSourceLocation(F, Record[0])); Tok.setLength(Record[1]); if (IdentifierInfo *II = getLocalIdentifier(F, Record[2])) Tok.setIdentifierInfo(II); Tok.setKind((tok::TokenKind)Record[3]); Tok.setFlag((Token::TokenFlags)Record[4]); Macro->AddTokenToBody(Tok); break; } } } } PreprocessedEntityID ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const { 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(const char *path) { return llvm::HashString(llvm::sys::path::filename(path)); } HeaderFileInfoTrait::internal_key_type HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; } bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) { if (strcmp(a, b) == 0) return true; if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b)) return false; // Determine whether the actual files are equivalent. bool Result = false; if (llvm::sys::fs::equivalent(a, b, Result)) return false; return Result; } std::pair HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); unsigned DataLen = (unsigned) *d++; return std::make_pair(KeyLen + 1, DataLen); } HeaderFileInfoTrait::data_type HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d, unsigned DataLen) { const unsigned char *End = d + DataLen; using namespace clang::io; HeaderFileInfo HFI; unsigned Flags = *d++; HFI.isImport = (Flags >> 5) & 0x01; HFI.isPragmaOnce = (Flags >> 4) & 0x01; HFI.DirInfo = (Flags >> 2) & 0x03; HFI.Resolved = (Flags >> 1) & 0x01; HFI.IndexHeaderMapHeader = Flags & 0x01; HFI.NumIncludes = ReadUnalignedLE16(d); HFI.ControllingMacroID = Reader.getGlobalIdentifierID(M, ReadUnalignedLE32(d)); if (unsigned FrameworkOffset = ReadUnalignedLE32(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 && "Wrong data length in HeaderFileInfo deserialization"); (void)End; // This HeaderFileInfo was externally loaded. HFI.External = true; return HFI; } void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ModuleFile &F, uint64_t LocalOffset, bool Visible) { if (Visible) { // Note that this identifier has a macro definition. II->setHasMacroDefinition(true); } // Adjust the offset to a global offset. UnreadMacroRecordOffsets[II] = F.GlobalBitOffset + LocalOffset; } void ASTReader::ReadDefinedMacros() { for (ModuleReverseIterator I = ModuleMgr.rbegin(), E = ModuleMgr.rend(); I != E; ++I) { llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor; // If there was no preprocessor block, skip this file. if (!MacroCursor.getBitStreamReader()) continue; llvm::BitstreamCursor Cursor = MacroCursor; Cursor.JumpToBit((*I)->MacroStartOffset); RecordData Record; while (true) { unsigned Code = Cursor.ReadCode(); if (Code == llvm::bitc::END_BLOCK) break; if (Code == llvm::bitc::ENTER_SUBBLOCK) { // No known subblocks, always skip them. Cursor.ReadSubBlockID(); if (Cursor.SkipBlock()) { Error("malformed block record in AST file"); return; } continue; } if (Code == llvm::bitc::DEFINE_ABBREV) { Cursor.ReadAbbrevRecord(); continue; } // Read a record. const char *BlobStart; unsigned BlobLen; Record.clear(); switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { default: // Default behavior: ignore. break; case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: getLocalIdentifier(**I, Record[0]); break; case PP_TOKEN: // Ignore tokens. break; } } } // Drain the unread macro-record offsets map. while (!UnreadMacroRecordOffsets.empty()) LoadMacroDefinition(UnreadMacroRecordOffsets.begin()); } void ASTReader::LoadMacroDefinition( llvm::DenseMap::iterator Pos) { assert(Pos != UnreadMacroRecordOffsets.end() && "Unknown macro definition"); uint64_t Offset = Pos->second; UnreadMacroRecordOffsets.erase(Pos); RecordLocation Loc = getLocalBitOffset(Offset); ReadMacroRecord(*Loc.F, Loc.Offset); } void ASTReader::LoadMacroDefinition(IdentifierInfo *II) { llvm::DenseMap::iterator Pos = UnreadMacroRecordOffsets.find(II); LoadMacroDefinition(Pos); } namespace { /// \brief Visitor class used to look up identifirs in an AST file. class IdentifierLookupVisitor { StringRef Name; unsigned PriorGeneration; IdentifierInfo *Found; public: IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration) : Name(Name), PriorGeneration(PriorGeneration), Found() { } static bool visit(ModuleFile &M, void *UserData) { IdentifierLookupVisitor *This = static_cast(UserData); // If we've already searched this module file, skip it now. if (M.Generation <= This->PriorGeneration) return true; ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; if (!IdTable) return false; ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), M, This->Found); std::pair Key(This->Name.begin(), This->Name.size()); ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &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. This->Found = *Pos; return true; } // \brief Retrieve the identifier info found within the module // files. IdentifierInfo *getIdentifierInfo() const { return Found; } }; } void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { unsigned PriorGeneration = 0; if (getContext().getLangOpts().Modules) PriorGeneration = IdentifierGeneration[&II]; IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration); ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); 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] = CurrentGeneration; } const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) { std::string Filename = filenameStrRef; MaybeAddSystemRootToFilename(Filename); const FileEntry *File = FileMgr.getFile(Filename); if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() && OriginalDir != CurrentDir) { std::string resolved = resolveFileRelativeToOriginalDir(Filename, OriginalDir, CurrentDir); if (!resolved.empty()) File = FileMgr.getFile(resolved); } return File; } /// \brief If we are loading a relocatable PCH file, and the filename is /// not an absolute path, add the system root to the beginning of the file /// name. void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) { // If this is not a relocatable PCH file, there's nothing to do. if (!RelocatablePCH) return; if (Filename.empty() || llvm::sys::path::is_absolute(Filename)) return; if (isysroot.empty()) { // If no system root was given, default to '/' Filename.insert(Filename.begin(), '/'); return; } unsigned Length = isysroot.size(); if (isysroot[Length - 1] != '/') Filename.insert(Filename.begin(), '/'); Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end()); } ASTReader::ASTReadResult ASTReader::ReadASTBlock(ModuleFile &F) { llvm::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 (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code == llvm::bitc::END_BLOCK) { if (Stream.ReadBlockEnd()) { Error("error at end of module block in AST file"); return Failure; } return Success; } if (Code == llvm::bitc::ENTER_SUBBLOCK) { switch (Stream.ReadSubBlockID()) { 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 DECL_UPDATES_BLOCK_ID: if (Stream.SkipBlock()) { 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(/*RecordConditionalDirectives=*/false); if (!PP.getPreprocessingRecord()->getExternalSource()) PP.getPreprocessingRecord()->SetExternalSource(*this); break; case SOURCE_MANAGER_BLOCK_ID: switch (ReadSourceManagerBlock(F)) { case Success: break; case Failure: Error("malformed source manager block in AST file"); return Failure; case IgnorePCH: return IgnorePCH; } break; case SUBMODULE_BLOCK_ID: switch (ReadSubmoduleBlock(F)) { case Success: break; case Failure: Error("malformed submodule block in AST file"); return Failure; case IgnorePCH: return IgnorePCH; } break; default: if (!Stream.SkipBlock()) break; Error("malformed block record in AST file"); return Failure; } continue; } if (Code == llvm::bitc::DEFINE_ABBREV) { Stream.ReadAbbrevRecord(); continue; } // Read and process a record. Record.clear(); const char *BlobStart = 0; unsigned BlobLen = 0; switch ((ASTRecordTypes)Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { default: // Default behavior: ignore. break; case METADATA: { if (Record[0] != VERSION_MAJOR && !DisableValidation) { Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old : diag::warn_pch_version_too_new); return IgnorePCH; } bool hasErrors = Record[5]; if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { Diag(diag::err_pch_with_compiler_errors); return IgnorePCH; } RelocatablePCH = Record[4]; if (Listener) { std::string TargetTriple(BlobStart, BlobLen); if (Listener->ReadTargetTriple(TargetTriple)) return IgnorePCH; } break; } case IMPORTS: { // 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++]; unsigned Length = Record[Idx++]; SmallString<128> ImportedFile(Record.begin() + Idx, Record.begin() + Idx + Length); Idx += Length; // Load the AST file. switch(ReadASTCore(ImportedFile, ImportedKind, &F)) { case Failure: return Failure; // If we have to ignore the dependency, we'll have to ignore this too. case IgnorePCH: return IgnorePCH; case Success: break; } } break; } case TYPE_OFFSET: { if (F.LocalNumTypes != 0) { Error("duplicate TYPE_OFFSET record in AST file"); return Failure; } F.TypeOffsets = (const uint32_t *)BlobStart; 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 *)BlobStart; 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(); DeclContextInfo &Info = F.DeclContextInfos[TU]; Info.LexicalDecls = reinterpret_cast(BlobStart); Info.NumLexicalDecls = static_cast(BlobLen / sizeof(KindDeclIDPair)); TU->setHasExternalLexicalStorage(true); break; } case UPDATE_VISIBLE: { unsigned Idx = 0; serialization::DeclID ID = ReadDeclID(F, Record, Idx); ASTDeclContextNameLookupTable *Table = ASTDeclContextNameLookupTable::Create( (const unsigned char *)BlobStart + Record[Idx++], (const unsigned char *)BlobStart, ASTDeclContextNameLookupTrait(*this, F)); if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU? DeclContext *TU = Context.getTranslationUnitDecl(); F.DeclContextInfos[TU].NameLookupTableData = Table; TU->setHasExternalVisibleStorage(true); } else PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F)); break; } case LANGUAGE_OPTIONS: if (ParseLanguageOptions(Record) && !DisableValidation) return IgnorePCH; break; case IDENTIFIER_TABLE: F.IdentifierTableData = BlobStart; if (Record[0]) { F.IdentifierLookupTable = ASTIdentifierLookupTable::Create( (const unsigned char *)F.IdentifierTableData + Record[0], (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 *)BlobStart; 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 EXTERNAL_DEFINITIONS: for (unsigned I = 0, N = Record.size(); I != N; ++I) ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I])); break; case SPECIAL_TYPES: for (unsigned I = 0, N = Record.size(); I != N; ++I) SpecialTypes.push_back(getGlobalTypeID(F, Record[I])); 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 LOCALLY_SCOPED_EXTERNAL_DECLS: for (unsigned I = 0, N = Record.size(); I != N; ++I) LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I])); break; case SELECTOR_OFFSETS: { F.SelectorOffsets = (const uint32_t *)BlobStart; 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 *)BlobStart; 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(Record[0]); break; case FILE_SORTED_DECLS: F.FileSortedDecls = (const DeclID *)BlobStart; break; case SOURCE_LOCATION_OFFSETS: { F.SLocEntryOffsets = (const uint32_t *)BlobStart; F.LocalNumSLocEntries = Record[0]; unsigned SLocSpaceSize = Record[1]; llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, SLocSpaceSize); // 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.insert(std::make_pair(0U, 0)); // This module. Base was 2 when being compiled. F.SLocRemap.insert(std::make_pair(2U, static_cast(F.SLocEntryBaseOffset - 2))); TotalNumSLocEntries += F.LocalNumSLocEntries; break; } case MODULE_OFFSET_MAP: { // Additional remapping information. const unsigned char *Data = (const unsigned char*)BlobStart; const unsigned char *DataEnd = Data + BlobLen; // Continuous range maps we may be updating in our module. ContinuousRangeMap::Builder SLocRemap(F.SLocRemap); ContinuousRangeMap::Builder IdentifierRemap(F.IdentifierRemap); ContinuousRangeMap::Builder PreprocessedEntityRemap(F.PreprocessedEntityRemap); ContinuousRangeMap::Builder SubmoduleRemap(F.SubmoduleRemap); ContinuousRangeMap::Builder SelectorRemap(F.SelectorRemap); ContinuousRangeMap::Builder DeclRemap(F.DeclRemap); ContinuousRangeMap::Builder TypeRemap(F.TypeRemap); while(Data < DataEnd) { uint16_t Len = io::ReadUnalignedLE16(Data); StringRef Name = StringRef((const char*)Data, Len); Data += Len; ModuleFile *OM = ModuleMgr.lookup(Name); if (!OM) { Error("SourceLocation remap refers to unknown module"); return Failure; } uint32_t SLocOffset = io::ReadUnalignedLE32(Data); uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data); uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data); uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data); uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data); uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data); uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data); // Source location offset is mapped to OM->SLocEntryBaseOffset. SLocRemap.insert(std::make_pair(SLocOffset, static_cast(OM->SLocEntryBaseOffset - SLocOffset))); IdentifierRemap.insert( std::make_pair(IdentifierIDOffset, OM->BaseIdentifierID - IdentifierIDOffset)); PreprocessedEntityRemap.insert( std::make_pair(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset)); SubmoduleRemap.insert(std::make_pair(SubmoduleIDOffset, OM->BaseSubmoduleID - SubmoduleIDOffset)); SelectorRemap.insert(std::make_pair(SelectorIDOffset, OM->BaseSelectorID - SelectorIDOffset)); DeclRemap.insert(std::make_pair(DeclIDOffset, OM->BaseDeclID - DeclIDOffset)); TypeRemap.insert(std::make_pair(TypeIndexOffset, OM->BaseTypeIndex - TypeIndexOffset)); // Global -> local mappings. F.GlobalToLocalDeclIDs[OM] = DeclIDOffset; } break; } case SOURCE_MANAGER_LINE_TABLE: if (ParseLineTable(F, Record)) return Failure; break; case FILE_SOURCE_LOCATION_OFFSETS: F.SLocFileOffsets = (const uint32_t *)BlobStart; F.LocalNumSLocFileEntries = Record[0]; 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 STAT_CACHE: { if (!DisableStatCache) { ASTStatCache *MyStatCache = new ASTStatCache((const unsigned char *)BlobStart + Record[0], (const unsigned char *)BlobStart, NumStatHits, NumStatMisses); FileMgr.addStatCache(MyStatCache); F.StatCache = MyStatCache; } 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 DYNAMIC_CLASSES: for (unsigned I = 0, N = Record.size(); I != N; ++I) DynamicClasses.push_back(getGlobalDeclID(F, Record[I])); break; case PENDING_IMPLICIT_INSTANTIATIONS: if (PendingInstantiations.size() % 2 != 0) { Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block"); return Failure; } // Later lists of pending instantiations overwrite earlier ones. // FIXME: This is most certainly wrong for modules. PendingInstantiations.clear(); 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: // Later tables overwrite earlier ones. // FIXME: Modules will have some trouble with this. SemaDeclRefs.clear(); for (unsigned I = 0, N = Record.size(); I != N; ++I) SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I])); break; case ORIGINAL_FILE_NAME: // The primary AST will be the last to get here, so it will be the one // that's used. ActualOriginalFileName.assign(BlobStart, BlobLen); OriginalFileName = ActualOriginalFileName; MaybeAddSystemRootToFilename(OriginalFileName); break; case ORIGINAL_FILE_ID: OriginalFileID = FileID::get(Record[0]); break; case ORIGINAL_PCH_DIR: // The primary AST will be the last to get here, so it will be the one // that's used. OriginalDir.assign(BlobStart, BlobLen); break; case VERSION_CONTROL_BRANCH_REVISION: { const std::string &CurBranch = getClangFullRepositoryVersion(); StringRef ASTBranch(BlobStart, BlobLen); if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch; return IgnorePCH; } break; } case PPD_ENTITIES_OFFSETS: { F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart; assert(BlobLen % sizeof(PPEntityOffset) == 0); F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset); unsigned LocalBasePreprocessedEntityID = Record[0]; unsigned StartingID; if (!PP.getPreprocessingRecord()) PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false); 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) DeclUpdateOffsets[getGlobalDeclID(F, Record[I])] .push_back(std::make_pair(&F, Record[I+1])); break; } case DECL_REPLACEMENTS: { if (Record.size() % 3 != 0) { Error("invalid DECL_REPLACEMENTS block in AST file"); return Failure; } for (unsigned I = 0, N = Record.size(); I != N; I += 3) ReplacedDecls[getGlobalDeclID(F, Record[I])] = ReplacedDeclInfo(&F, Record[I+1], Record[I+2]); 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 *)BlobStart; break; } case OBJC_CATEGORIES: F.ObjCCategories.swap(Record); break; case CXX_BASE_SPECIFIER_OFFSETS: { if (F.LocalNumCXXBaseSpecifiers != 0) { Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file"); return Failure; } F.LocalNumCXXBaseSpecifiers = Record[0]; F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart; NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers; break; } case DIAG_PRAGMA_MAPPINGS: if (Record.size() % 2 != 0) { Error("invalid DIAG_USER_MAPPINGS block in AST file"); return Failure; } if (F.PragmaDiagMappings.empty()) F.PragmaDiagMappings.swap(Record); else F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(), Record.begin(), Record.end()); 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 = BlobStart; F.LocalNumHeaderFileInfos = Record[1]; F.HeaderFileFrameworkStrings = BlobStart + Record[2]; if (Record[0]) { F.HeaderFileInfoTable = HeaderFileInfoLookupTable::Create( (const unsigned char *)F.HeaderFileInfoTableData + Record[0], (const unsigned char *)F.HeaderFileInfoTableData, HeaderFileInfoTrait(*this, F, &PP.getHeaderSearchInfo(), BlobStart + 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: // Later tables overwrite earlier ones. OpenCLExtensions.swap(Record); 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 IMPORTED_MODULES: { if (F.Kind != MK_Module) { // 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; ++I) { if (unsigned GlobalID = getGlobalSubmoduleID(F, Record[I])) ImportedModules.push_back(GlobalID); } } break; } case LOCAL_REDECLARATIONS: { F.RedeclarationChains.swap(Record); break; } case LOCAL_REDECLARATIONS_MAP: { if (F.LocalNumRedeclarationsInMap != 0) { Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file"); return Failure; } F.LocalNumRedeclarationsInMap = Record[0]; F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart; break; } case MERGED_DECLARATIONS: { for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) { GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]); SmallVectorImpl &Decls = StoredMergedDecls[CanonID]; for (unsigned N = Record[Idx++]; N > 0; --N) Decls.push_back(getGlobalDeclID(F, Record[Idx++])); } break; } } } Error("premature end of bitstream in AST file"); return Failure; } ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) { llvm::BitstreamCursor &SLocEntryCursor = M.SLocEntryCursor; for (unsigned i = 0, e = M.LocalNumSLocFileEntries; i != e; ++i) { SLocEntryCursor.JumpToBit(M.SLocFileOffsets[i]); unsigned Code = SLocEntryCursor.ReadCode(); if (Code == llvm::bitc::END_BLOCK || Code == llvm::bitc::ENTER_SUBBLOCK || Code == llvm::bitc::DEFINE_ABBREV) { Error("incorrectly-formatted source location entry in AST file"); return Failure; } RecordData Record; const char *BlobStart; unsigned BlobLen; switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { default: Error("incorrectly-formatted source location entry in AST file"); return Failure; case SM_SLOC_FILE_ENTRY: { // If the buffer was overridden, the file need not exist. if (Record[6]) break; StringRef Filename(BlobStart, BlobLen); const FileEntry *File = getFileEntry(Filename); if (File == 0) { std::string ErrorStr = "could not find file '"; ErrorStr += Filename; ErrorStr += "' referenced by AST file"; Error(ErrorStr.c_str()); return IgnorePCH; } if (Record.size() < 7) { Error("source location entry is incorrect"); return Failure; } // The stat info from the FileEntry came from the cached stat // info of the PCH, so we cannot trust it. struct stat StatBuf; if (::stat(File->getName(), &StatBuf) != 0) { StatBuf.st_size = File->getSize(); StatBuf.st_mtime = File->getModificationTime(); } if (((off_t)Record[4] != StatBuf.st_size #if !defined(LLVM_ON_WIN32) // In our regression testing, the Windows file system seems to // have inconsistent modification times that sometimes // erroneously trigger this error-handling path. || (time_t)Record[5] != StatBuf.st_mtime #endif )) { Error(diag::err_fe_pch_file_modified, Filename); return IgnorePCH; } break; } } } return Success; } void ASTReader::makeNamesVisible(const HiddenNames &Names) { for (unsigned I = 0, N = Names.size(); I != N; ++I) { if (Decl *D = Names[I].dyn_cast()) D->Hidden = false; else { IdentifierInfo *II = Names[I].get(); if (!II->hasMacroDefinition()) { II->setHasMacroDefinition(true); if (DeserializationListener) DeserializationListener->MacroVisible(II); } } } } void ASTReader::makeModuleVisible(Module *Mod, Module::NameVisibilityKind NameVisibility) { llvm::SmallPtrSet Visited; llvm::SmallVector Stack; Stack.push_back(Mod); while (!Stack.empty()) { Mod = Stack.back(); Stack.pop_back(); 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()) { makeNamesVisible(Hidden->second); HiddenNamesMap.erase(Hidden); } // Push any non-explicit submodules onto the stack to be marked as // visible. for (Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); Sub != SubEnd; ++Sub) { if (!(*Sub)->IsExplicit && Visited.insert(*Sub)) Stack.push_back(*Sub); } // Push any exported modules onto the stack to be marked as visible. bool AnyWildcard = false; bool UnrestrictedWildcard = false; llvm::SmallVector WildcardRestrictions; for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) { Module *Exported = Mod->Exports[I].getPointer(); if (!Mod->Exports[I].getInt()) { // Export a named module directly; no wildcards involved. if (Visited.insert(Exported)) Stack.push_back(Exported); continue; } // Wildcard export: export all of the imported modules that match // the given pattern. AnyWildcard = true; if (UnrestrictedWildcard) continue; if (Module *Restriction = Mod->Exports[I].getPointer()) WildcardRestrictions.push_back(Restriction); else { WildcardRestrictions.clear(); UnrestrictedWildcard = true; } } // If there were any wildcards, push any imported modules that were // re-exported by the wildcard restriction. if (!AnyWildcard) continue; for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) { Module *Imported = Mod->Imports[I]; if (Visited.count(Imported)) continue; bool Acceptable = UnrestrictedWildcard; if (!Acceptable) { // Check whether this module meets one of the restrictions. for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) { Module *Restriction = WildcardRestrictions[R]; if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) { Acceptable = true; break; } } } if (!Acceptable) continue; Visited.insert(Imported); Stack.push_back(Imported); } } } ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, ModuleKind Type) { // Bump the generation number. unsigned PreviousGeneration = CurrentGeneration++; switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) { case Failure: return Failure; case IgnorePCH: return IgnorePCH; case Success: break; } // Here comes stuff that we only do once the entire chain is loaded. // Check the predefines buffers. if (!DisableValidation && Type == MK_PCH && // FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines; // if DisableValidation is true, defines that were set on command-line // but not in the PCH file will not be added to SuggestedPredefines. CheckPredefinesBuffers()) return IgnorePCH; // 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 (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(), IdEnd = PP.getIdentifierTable().end(); Id != IdEnd; ++Id) Id->second->setOutOfDate(true); // Resolve any unresolved module exports. for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) { UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I]; SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID); Module *ResolvedMod = getSubmodule(GlobalID); if (Unresolved.IsImport) { if (ResolvedMod) Unresolved.Mod->Imports.push_back(ResolvedMod); continue; } if (ResolvedMod || Unresolved.IsWildcard) Unresolved.Mod->Exports.push_back( Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard)); } UnresolvedModuleImportExports.clear(); InitializeContext(); if (DeserializationListener) DeserializationListener->ReaderInitialized(this); if (!OriginalFileID.isInvalid()) { OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID + OriginalFileID.getOpaqueValue() - 1); // 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(OriginalFileID); } else if (Type == MK_MainFile) { SourceMgr.setMainFileID(OriginalFileID); } } // 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); } return Success; } ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, ModuleKind Type, ModuleFile *ImportedBy) { ModuleFile *M; bool NewModule; std::string ErrorStr; llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy, CurrentGeneration, ErrorStr); if (!M) { // We couldn't load the module. std::string Msg = "Unable to load module \"" + FileName.str() + "\": " + ErrorStr; Error(Msg); return Failure; } if (!NewModule) { // We've already loaded this module. return Success; } // 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; llvm::BitstreamCursor &Stream = F.Stream; Stream.init(F.StreamFile); F.SizeInBits = F.Buffer->getBufferSize() * 8; // Sniff for the signature. if (Stream.Read(8) != 'C' || Stream.Read(8) != 'P' || Stream.Read(8) != 'C' || Stream.Read(8) != 'H') { Diag(diag::err_not_a_pch_file) << FileName; return Failure; } while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code != llvm::bitc::ENTER_SUBBLOCK) { Error("invalid record at top-level of AST file"); return Failure; } unsigned BlockID = Stream.ReadSubBlockID(); // We only know the AST subblock ID. switch (BlockID) { case llvm::bitc::BLOCKINFO_BLOCK_ID: if (Stream.ReadBlockInfoBlock()) { Error("malformed BlockInfoBlock in AST file"); return Failure; } break; case AST_BLOCK_ID: switch (ReadASTBlock(F)) { case Success: break; case Failure: return Failure; case IgnorePCH: // FIXME: We could consider reading through to the end of this // AST block, skipping subblocks, to see if there are other // AST blocks elsewhere. // FIXME: We can't clear loaded slocentries anymore. //SourceMgr.ClearPreallocatedSLocEntries(); // Remove the stat cache. if (F.StatCache) FileMgr.removeStatCache((ASTStatCache*)F.StatCache); return IgnorePCH; } break; default: if (Stream.SkipBlock()) { Error("malformed block record in AST file"); return Failure; } break; } } // 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)); // Make sure that the files this module was built against are still available. if (!DisableValidation) { switch(validateFileEntries(*M)) { case Failure: return Failure; case IgnorePCH: return IgnorePCH; case Success: break; } } // Preload SLocEntries. for (unsigned I = 0, N = M->PreloadSLocEntries.size(); I != N; ++I) { int Index = int(M->PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; // Load it through the SourceManager and don't call ReadSLocEntryRecord() // directly because the entry may have already been loaded in which case // calling ReadSLocEntryRecord() directly would trigger an assertion in // SourceManager. SourceMgr.getLoadedSLocEntryByID(Index); } 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()); // Make sure we load the declaration update records for the translation unit, // if there are any. loadDeclUpdateRecords(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 (Context.getBuiltinVaListType().isNull()) { Context.setBuiltinVaListType( GetType(SpecialTypes[SPECIAL_TYPE_BUILTIN_VA_LIST])); } 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. for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) { if (Module *Imported = getSubmodule(ImportedModules[I])) makeModuleVisible(Imported, Module::AllVisible); } ImportedModules.clear(); } void ASTReader::finalizeForWriting() { for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(), HiddenEnd = HiddenNamesMap.end(); Hidden != HiddenEnd; ++Hidden) { makeNamesVisible(Hidden->second); } HiddenNamesMap.clear(); } /// \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, DiagnosticsEngine &Diags) { // Open the AST file. std::string ErrStr; OwningPtr Buffer; Buffer.reset(FileMgr.getBufferForFile(ASTFileName, &ErrStr)); if (!Buffer) { Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr; return std::string(); } // Initialize the stream llvm::BitstreamReader StreamFile; llvm::BitstreamCursor Stream; StreamFile.init((const unsigned char *)Buffer->getBufferStart(), (const unsigned char *)Buffer->getBufferEnd()); Stream.init(StreamFile); // Sniff for the signature. if (Stream.Read(8) != 'C' || Stream.Read(8) != 'P' || Stream.Read(8) != 'C' || Stream.Read(8) != 'H') { Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName; return std::string(); } RecordData Record; while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code == llvm::bitc::ENTER_SUBBLOCK) { unsigned BlockID = Stream.ReadSubBlockID(); // We only know the AST subblock ID. switch (BlockID) { case AST_BLOCK_ID: if (Stream.EnterSubBlock(AST_BLOCK_ID)) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } break; default: if (Stream.SkipBlock()) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } break; } continue; } if (Code == llvm::bitc::END_BLOCK) { if (Stream.ReadBlockEnd()) { Diags.Report(diag::err_fe_pch_error_at_end_block) << ASTFileName; return std::string(); } continue; } if (Code == llvm::bitc::DEFINE_ABBREV) { Stream.ReadAbbrevRecord(); continue; } Record.clear(); const char *BlobStart = 0; unsigned BlobLen = 0; if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE_NAME) return std::string(BlobStart, BlobLen); } return std::string(); } ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { // 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 = 0; RecordData Record; while (true) { unsigned Code = F.Stream.ReadCode(); if (Code == llvm::bitc::END_BLOCK) { if (F.Stream.ReadBlockEnd()) { Error("error at end of submodule block in AST file"); return Failure; } return Success; } if (Code == llvm::bitc::ENTER_SUBBLOCK) { // No known subblocks, always skip them. F.Stream.ReadSubBlockID(); if (F.Stream.SkipBlock()) { Error("malformed block record in AST file"); return Failure; } continue; } if (Code == llvm::bitc::DEFINE_ABBREV) { F.Stream.ReadAbbrevRecord(); continue; } // Read a record. const char *BlobStart; unsigned BlobLen; Record.clear(); switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { default: // Default behavior: ignore. break; case SUBMODULE_DEFINITION: { if (First) { Error("missing submodule metadata record at beginning of block"); return Failure; } if (Record.size() < 7) { Error("malformed module definition"); return Failure; } StringRef Name(BlobStart, BlobLen); SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]); SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]); bool IsFramework = Record[2]; bool IsExplicit = Record[3]; bool IsSystem = Record[4]; bool InferSubmodules = Record[5]; bool InferExplicitSubmodules = Record[6]; bool InferExportWildcard = Record[7]; Module *ParentModule = 0; 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; SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS; if (GlobalIndex >= SubmodulesLoaded.size() || SubmodulesLoaded[GlobalIndex]) { Error("too many submodules"); return Failure; } CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; CurrentModule->InferSubmodules = InferSubmodules; CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; CurrentModule->InferExportWildcard = InferExportWildcard; if (DeserializationListener) DeserializationListener->ModuleRead(GlobalID, CurrentModule); SubmodulesLoaded[GlobalIndex] = CurrentModule; break; } case SUBMODULE_UMBRELLA_HEADER: { if (First) { Error("missing submodule metadata record at beginning of block"); return Failure; } if (!CurrentModule) break; StringRef FileName(BlobStart, BlobLen); if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) { if (!CurrentModule->getUmbrellaHeader()) ModMap.setUmbrellaHeader(CurrentModule, Umbrella); else if (CurrentModule->getUmbrellaHeader() != Umbrella) { Error("mismatched umbrella headers in submodule"); return Failure; } } break; } case SUBMODULE_HEADER: { if (First) { Error("missing submodule metadata record at beginning of block"); return Failure; } if (!CurrentModule) break; // FIXME: Be more lazy about this! StringRef FileName(BlobStart, BlobLen); if (const FileEntry *File = PP.getFileManager().getFile(FileName)) { if (std::find(CurrentModule->Headers.begin(), CurrentModule->Headers.end(), File) == CurrentModule->Headers.end()) ModMap.addHeader(CurrentModule, File); } break; } case SUBMODULE_UMBRELLA_DIR: { if (First) { Error("missing submodule metadata record at beginning of block"); return Failure; } if (!CurrentModule) break; StringRef DirName(BlobStart, BlobLen); if (const DirectoryEntry *Umbrella = PP.getFileManager().getDirectory(DirName)) { if (!CurrentModule->getUmbrellaDir()) ModMap.setUmbrellaDir(CurrentModule, Umbrella); else if (CurrentModule->getUmbrellaDir() != Umbrella) { Error("mismatched umbrella directories in submodule"); return Failure; } } break; } case SUBMODULE_METADATA: { if (!First) { Error("submodule metadata record not at beginning of block"); return Failure; } First = false; 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); } break; } case SUBMODULE_IMPORTS: { if (First) { Error("missing submodule metadata record at beginning of block"); return Failure; } if (!CurrentModule) break; for (unsigned Idx = 0; Idx != Record.size(); ++Idx) { UnresolvedModuleImportExport Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; Unresolved.IsImport = true; Unresolved.IsWildcard = false; UnresolvedModuleImportExports.push_back(Unresolved); } break; } case SUBMODULE_EXPORTS: { if (First) { Error("missing submodule metadata record at beginning of block"); return Failure; } if (!CurrentModule) break; for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) { UnresolvedModuleImportExport Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; Unresolved.IsImport = false; Unresolved.IsWildcard = Record[Idx + 1]; UnresolvedModuleImportExports.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: { if (First) { Error("missing submodule metadata record at beginning of block"); return Failure; } if (!CurrentModule) break; CurrentModule->addRequirement(StringRef(BlobStart, BlobLen), Context.getLangOpts(), Context.getTargetInfo()); 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 SmallVectorImpl &Record) { if (Listener) { 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" unsigned Length = Record[Idx++]; LangOpts.CurrentModule.assign(Record.begin() + Idx, Record.begin() + Idx + Length); return Listener->ReadLanguageOptions(LangOpts); } return false; } 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); } 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]; SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor); M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset); unsigned Code = M.PreprocessorDetailCursor.ReadCode(); switch (Code) { case llvm::bitc::END_BLOCK: return 0; case llvm::bitc::ENTER_SUBBLOCK: Error("unexpected subblock record in preprocessor detail block"); return 0; case llvm::bitc::DEFINE_ABBREV: Error("unexpected abbrevation record in preprocessor detail block"); return 0; default: break; } if (!PP.getPreprocessingRecord()) { Error("no preprocessing record"); return 0; } // Read the record. SourceRange Range(ReadSourceLocation(M, PPOffs.Begin), ReadSourceLocation(M, PPOffs.End)); PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); const char *BlobStart = 0; unsigned BlobLen = 0; RecordData Record; PreprocessorDetailRecordTypes RecType = (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord( Code, Record, BlobStart, BlobLen); switch (RecType) { case PPD_MACRO_EXPANSION: { bool isBuiltin = Record[0]; IdentifierInfo *Name = 0; MacroDefinition *Def = 0; 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]); MacroDefinition *MD = new (PPRec) MacroDefinition(II, Range); if (DeserializationListener) DeserializationListener->MacroDefinitionRead(PPID, MD); return MD; } case PPD_INCLUSION_DIRECTIVE: { const char *FullFileNameStart = BlobStart + Record[0]; StringRef FullFileName(FullFileNameStart, BlobLen - Record[0]); const FileEntry *File = 0; 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(BlobStart, Record[0]), Record[1], 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 getGlobalPreprocessedEntityID(M, M.BasePreprocessedEntityID); } return getTotalNumPreprocessedEntities(); } namespace { template 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.ReadSourceLocation(M, PPE.*PPLoc); } }; } /// \brief Returns the first preprocessed entity ID that ends after \arg BLoc. PreprocessedEntityID ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const { if (SourceMgr.isLocalSourceLocation(BLoc)) return getTotalNumPreprocessedEntities(); GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - BLoc.getOffset()); 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; // 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(ReadSourceLocation(M, PPI->End), BLoc)){ First = PPI; ++First; Count = Count - Half - 1; } else Count = Half; } if (PPI == pp_end) return findNextPreprocessedEntity(SLocMapI); return getGlobalPreprocessedEntityID(M, M.BasePreprocessedEntityID + (PPI - pp_begin)); } /// \brief Returns the first preprocessed entity ID that begins after \arg ELoc. PreprocessedEntityID ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const { if (SourceMgr.isLocalSourceLocation(ELoc)) return getTotalNumPreprocessedEntities(); GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - ELoc.getOffset()); 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; pp_iterator PPI = std::upper_bound(pp_begin, pp_end, ELoc, PPEntityComp<&PPEntityOffset::Begin>(*this, M)); if (PPI == pp_end) return findNextPreprocessedEntity(SLocMapI); return getGlobalPreprocessedEntityID(M, 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 = findBeginPreprocessedEntity(Range.getBegin()); PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd()); 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. llvm::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 = ReadSourceLocation(M, PPOffs.Begin); 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 { ASTReader &Reader; const FileEntry *FE; llvm::Optional HFI; public: HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE) : Reader(Reader), FE(FE) { } static bool visit(ModuleFile &M, void *UserData) { HeaderFileInfoVisitor *This = static_cast(UserData); HeaderFileInfoTrait Trait(This->Reader, M, &This->Reader.getPreprocessor().getHeaderSearchInfo(), M.HeaderFileFrameworkStrings, This->FE->getName()); 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(This->FE->getName(), &Trait); if (Pos == Table->end()) return false; This->HFI = *Pos; return true; } llvm::Optional getHeaderFileInfo() const { return HFI; } }; } HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { HeaderFileInfoVisitor Visitor(*this, FE); ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor); if (llvm::Optional HFI = Visitor.getHeaderFileInfo()) { if (Listener) Listener->ReadHeaderFileInfo(*HFI, FE->getUID()); return *HFI; } return HeaderFileInfo(); } void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) { ModuleFile &F = *(*I); unsigned Idx = 0; while (Idx < F.PragmaDiagMappings.size()) { SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]); Diag.DiagStates.push_back(*Diag.GetCurDiagState()); Diag.DiagStatePoints.push_back( DiagnosticsEngine::DiagStatePoint(&Diag.DiagStates.back(), FullSourceLoc(Loc, SourceMgr))); while (1) { assert(Idx < F.PragmaDiagMappings.size() && "Invalid data, didn't find '-1' marking end of diag/map pairs"); if (Idx >= F.PragmaDiagMappings.size()) { break; // Something is messed up but at least avoid infinite loop in // release build. } unsigned DiagID = F.PragmaDiagMappings[Idx++]; if (DiagID == (unsigned)-1) { break; // no more diag/map pairs for this location. } diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++]; DiagnosticMappingInfo MappingInfo = Diag.makeMappingInfo(Map, Loc); Diag.GetCurDiagState()->setMappingInfo(DiagID, MappingInfo); } } } } /// \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); llvm::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_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() != 6) { 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]); 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]); unsigned Idx = 6; unsigned NumParams = Record[Idx++]; SmallVector ParamTypes; for (unsigned I = 0; I != NumParams; ++I) ParamTypes.push_back(readType(*Loc.F, Record, Idx)); EPI.Variadic = Record[Idx++]; EPI.HasTrailingReturn = Record[Idx++]; EPI.TypeQuals = Record[Idx++]; EPI.RefQualifier = static_cast(Record[Idx++]); ExceptionSpecificationType EST = static_cast(Record[Idx++]); EPI.ExceptionSpecType = EST; SmallVector Exceptions; if (EST == EST_Dynamic) { EPI.NumExceptions = Record[Idx++]; for (unsigned I = 0; I != EPI.NumExceptions; ++I) Exceptions.push_back(readType(*Loc.F, Record, Idx)); EPI.Exceptions = Exceptions.data(); } else if (EST == EST_ComputedNoexcept) { EPI.NoexceptExpr = ReadExpr(*Loc.F); + } else if (EST == EST_Uninstantiated) { + EPI.ExceptionSpecDecl = ReadDeclAs(*Loc.F, Record, Idx); + EPI.ExceptionSpecTemplate = ReadDeclAs(*Loc.F, Record, Idx); } return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams, 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: return Context.getAutoType(readType(*Loc.F, Record, Idx)); 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(); llvm::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_OBJECT: { unsigned Idx = 0; QualType Base = 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)); return Context.getObjCObjectType(Base, Protos.data(), NumProtos); } 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), 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. return QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 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 = this->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 = this->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.size(), Args.data()); } 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.data(), Args.size()); else T = Context.getTemplateSpecializationType(Name, Args.data(), Args.size(), 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); } } llvm_unreachable("Invalid TypeCode!"); } class clang::TypeLocReader : public TypeLocVisitor { ASTReader &Reader; ModuleFile &F; llvm::BitstreamCursor &DeclsCursor; const ASTReader::RecordData &Record; unsigned &Idx; SourceLocation ReadSourceLocation(const ASTReader::RecordData &R, unsigned &I) { return Reader.ReadSourceLocation(F, R, I); } template T *ReadDeclAs(const ASTReader::RecordData &Record, unsigned &Idx) { return Reader.ReadDeclAs(F, Record, Idx); } public: TypeLocReader(ASTReader &Reader, ModuleFile &F, const ASTReader::RecordData &Record, unsigned &Idx) : Reader(Reader), F(F), DeclsCursor(F.DeclsCursor), 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(Record, Idx)); 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(Record, Idx)); } void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { TL.setCaretLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { TL.setAmpLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { TL.setAmpAmpLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation(Record, Idx)); TL.setClassTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); } void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { TL.setLBracketLoc(ReadSourceLocation(Record, Idx)); TL.setRBracketLoc(ReadSourceLocation(Record, Idx)); if (Record[Idx++]) TL.setSizeExpr(Reader.ReadExpr(F)); else TL.setSizeExpr(0); } 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(Record, Idx)); } void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx)); TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx)); TL.setTrailingReturn(Record[Idx++]); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { TL.setArg(i, ReadDeclAs(Record, Idx)); } } void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { TL.setTypeofLoc(ReadSourceLocation(Record, Idx)); TL.setLParenLoc(ReadSourceLocation(Record, Idx)); TL.setRParenLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { TL.setTypeofLoc(ReadSourceLocation(Record, Idx)); TL.setLParenLoc(ReadSourceLocation(Record, Idx)); TL.setRParenLoc(ReadSourceLocation(Record, Idx)); TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); } void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { TL.setKWLoc(ReadSourceLocation(Record, Idx)); TL.setLParenLoc(ReadSourceLocation(Record, Idx)); TL.setRParenLoc(ReadSourceLocation(Record, Idx)); TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); } void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { TL.setAttrNameLoc(ReadSourceLocation(Record, Idx)); if (TL.hasAttrOperand()) { SourceRange range; range.setBegin(ReadSourceLocation(Record, Idx)); range.setEnd(ReadSourceLocation(Record, Idx)); TL.setAttrOperandParensRange(range); } if (TL.hasAttrExprOperand()) { if (Record[Idx++]) TL.setAttrExprOperand(Reader.ReadExpr(F)); else TL.setAttrExprOperand(0); } else if (TL.hasAttrEnumOperand()) TL.setAttrEnumOperandLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( SubstTemplateTypeParmTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc( SubstTemplateTypeParmPackTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx)); TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx)); TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); 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(Record, Idx)); TL.setRParenLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx)); TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); } void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx)); TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx)); TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx)); TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx)); TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); 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(Record, Idx)); } void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { TL.setHasBaseTypeAsWritten(Record[Idx++]); TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { TL.setKWLoc(ReadSourceLocation(Record, Idx)); TL.setLParenLoc(ReadSourceLocation(Record, Idx)); TL.setRParenLoc(ReadSourceLocation(Record, Idx)); } TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F, const RecordData &Record, unsigned &Idx) { QualType InfoTy = readType(F, Record, Idx); if (InfoTy.isNull()) return 0; TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy); TypeLocReader TLR(*this, F, 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_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; 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; } 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; 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::Pack: 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)); } Decl *ASTReader::GetExternalDecl(uint32_t ID) { return GetDecl(ID); } uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record, unsigned &Idx){ if (Idx >= Record.size()) return 0; unsigned LocalID = Record[Idx++]; return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]); } CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { RecordLocation Loc = getLocalBitOffset(Offset); llvm::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 0; } 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, unsigned LocalID) const { if (LocalID < NUM_PREDEF_DECL_IDS) return LocalID; 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 { GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID); assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); return &M == I->second; } ModuleFile *ASTReader::getOwningModuleFile(Decl *D) { if (!D->isFromASTFile()) return 0; 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(); unsigned RawLocation = 0; RecordLocation Rec = DeclCursorForID(ID, RawLocation); return ReadSourceLocation(*Rec.F, RawLocation); } Decl *ASTReader::GetDecl(DeclID ID) { if (ID < NUM_PREDEF_DECL_IDS) { switch ((PredefinedDeclIDs)ID) { case PREDEF_DECL_NULL_ID: return 0; 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(); } } unsigned Index = ID - NUM_PREDEF_DECL_IDS; if (Index >= DeclsLoaded.size()) { Error("declaration ID out-of-range for AST file"); } 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); return ReadStmtFromStream(*Loc.F); } namespace { class FindExternalLexicalDeclsVisitor { ASTReader &Reader; const DeclContext *DC; bool (*isKindWeWant)(Decl::Kind); SmallVectorImpl &Decls; bool PredefsVisited[NUM_PREDEF_DECL_IDS]; public: FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), SmallVectorImpl &Decls) : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls) { for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I) PredefsVisited[I] = false; } static bool visit(ModuleFile &M, bool Preorder, void *UserData) { if (Preorder) return false; FindExternalLexicalDeclsVisitor *This = static_cast(UserData); ModuleFile::DeclContextInfosMap::iterator Info = M.DeclContextInfos.find(This->DC); if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls) return false; // Load all of the declaration IDs for (const KindDeclIDPair *ID = Info->second.LexicalDecls, *IDE = ID + Info->second.NumLexicalDecls; ID != IDE; ++ID) { if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first)) continue; // Don't add predefined declarations to the lexical context more // than once. if (ID->second < NUM_PREDEF_DECL_IDS) { if (This->PredefsVisited[ID->second]) continue; This->PredefsVisited[ID->second] = true; } if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) { if (!This->DC->isDeclInLexicalTraversal(D)) This->Decls.push_back(D); } } return false; } }; } ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), SmallVectorImpl &Decls) { // There might be lexical decls in multiple modules, for the TU at // least. Walk all of the modules in the order they were loaded. FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls); ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor); ++NumLexicalDeclContextsRead; return ELR_Success; } 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))); } }; } 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))); } namespace { /// \brief ModuleFile visitor used to perform name lookup into a /// declaration context. class DeclContextNameLookupVisitor { ASTReader &Reader; llvm::SmallVectorImpl &Contexts; const DeclContext *DC; DeclarationName Name; SmallVectorImpl &Decls; public: DeclContextNameLookupVisitor(ASTReader &Reader, SmallVectorImpl &Contexts, DeclarationName Name, SmallVectorImpl &Decls) : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { } static bool visit(ModuleFile &M, void *UserData) { DeclContextNameLookupVisitor *This = static_cast(UserData); // Check whether we have any visible declaration information for // this context in this module. ModuleFile::DeclContextInfosMap::iterator Info; bool FoundInfo = false; for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) { Info = M.DeclContextInfos.find(This->Contexts[I]); if (Info != M.DeclContextInfos.end() && Info->second.NameLookupTableData) { FoundInfo = true; break; } } if (!FoundInfo) return false; // Look for this name within this module. ASTDeclContextNameLookupTable *LookupTable = Info->second.NameLookupTableData; ASTDeclContextNameLookupTable::iterator Pos = LookupTable->find(This->Name); if (Pos == LookupTable->end()) return false; bool FoundAnything = false; ASTDeclContextNameLookupTrait::data_type Data = *Pos; for (; Data.first != Data.second; ++Data.first) { NamedDecl *ND = This->Reader.GetLocalDeclAs(M, *Data.first); if (!ND) continue; if (ND->getDeclName() != This->Name) { assert(!This->Name.getCXXNameType().isNull() && "Name mismatch without a type"); continue; } // Record this declaration. FoundAnything = true; This->Decls.push_back(ND); } return FoundAnything; } }; } DeclContext::lookup_result ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { assert(DC->hasExternalVisibleStorage() && "DeclContext has no visible decls in storage"); if (!Name) return DeclContext::lookup_result(DeclContext::lookup_iterator(0), DeclContext::lookup_iterator(0)); SmallVector Decls; // Compute the declaration contexts we need to look into. Multiple such // declaration contexts occur when two declaration contexts from disjoint // modules get merged, e.g., when two namespaces with the same name are // independently defined in separate modules. SmallVector Contexts; Contexts.push_back(DC); if (DC->isNamespace()) { MergedDeclsMap::iterator Merged = MergedDecls.find(const_cast(cast(DC))); if (Merged != MergedDecls.end()) { for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) Contexts.push_back(cast(GetDecl(Merged->second[I]))); } } DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls); ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); ++NumVisibleDeclContextsRead; SetExternalVisibleDeclsForName(DC, Name, Decls); return const_cast(DC)->lookup(Name); } namespace { /// \brief ModuleFile visitor used to retrieve all visible names in a /// declaration context. class DeclContextAllNamesVisitor { ASTReader &Reader; llvm::SmallVectorImpl &Contexts; const DeclContext *DC; llvm::DenseMap > &Decls; public: DeclContextAllNamesVisitor(ASTReader &Reader, SmallVectorImpl &Contexts, llvm::DenseMap > &Decls) : Reader(Reader), Contexts(Contexts), Decls(Decls) { } static bool visit(ModuleFile &M, void *UserData) { DeclContextAllNamesVisitor *This = static_cast(UserData); // Check whether we have any visible declaration information for // this context in this module. ModuleFile::DeclContextInfosMap::iterator Info; bool FoundInfo = false; for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) { Info = M.DeclContextInfos.find(This->Contexts[I]); if (Info != M.DeclContextInfos.end() && Info->second.NameLookupTableData) { FoundInfo = true; break; } } if (!FoundInfo) return false; ASTDeclContextNameLookupTable *LookupTable = Info->second.NameLookupTableData; bool FoundAnything = false; for (ASTDeclContextNameLookupTable::data_iterator I = LookupTable->data_begin(), E = LookupTable->data_end(); I != E; ++I) { ASTDeclContextNameLookupTrait::data_type Data = *I; for (; Data.first != Data.second; ++Data.first) { NamedDecl *ND = This->Reader.GetLocalDeclAs(M, *Data.first); if (!ND) continue; // Record this declaration. FoundAnything = true; This->Decls[ND->getDeclName()].push_back(ND); } } return FoundAnything; } }; } void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { if (!DC->hasExternalVisibleStorage()) return; llvm::DenseMap > Decls; // Compute the declaration contexts we need to look into. Multiple such // declaration contexts occur when two declaration contexts from disjoint // modules get merged, e.g., when two namespaces with the same name are // independently defined in separate modules. SmallVector Contexts; Contexts.push_back(DC); if (DC->isNamespace()) { MergedDeclsMap::iterator Merged = MergedDecls.find(const_cast(cast(DC))); if (Merged != MergedDecls.end()) { for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) Contexts.push_back(cast(GetDecl(Merged->second[I]))); } } DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls); ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor); ++NumVisibleDeclContextsRead; for (llvm::DenseMap >::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { SetExternalVisibleDeclsForName(DC, I->first, 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 (ObjCImplDecl::method_iterator I = ImplD->meth_begin(), E = ImplD->meth_end(); I != E; ++I) Consumer->HandleInterestingDecl(DeclGroupRef(*I)); Consumer->HandleInterestingDecl(DeclGroupRef(ImplD)); } void ASTReader::PassInterestingDeclsToConsumer() { assert(Consumer); while (!InterestingDecls.empty()) { Decl *D = InterestingDecls.front(); InterestingDecls.pop_front(); PassInterestingDeclToConsumer(D); } } 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) return; for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) { // Force deserialization of this decl, which will cause it to be queued for // passing to the consumer. GetDecl(ExternalDefinitions[I]); } ExternalDefinitions.clear(); PassInterestingDeclsToConsumer(); } 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 *)0); unsigned NumIdentifiersLoaded = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(), IdentifiersLoaded.end(), (IdentifierInfo *)0); unsigned NumSelectorsLoaded = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(), SelectorsLoaded.end(), Selector()); std::fprintf(stderr, " %u stat cache hits\n", NumStatHits); std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses); 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 (!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)); std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses); } std::fprintf(stderr, "\n"); dump(); std::fprintf(stderr, "\n"); } template 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"; } } 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 submodule map", GlobalSubmoduleMap); dumpModuleIDMap("Global selector map", GlobalSelectorMap); dumpModuleIDMap("Global preprocessed entity map", GlobalPreprocessedEntityMap); llvm::errs() << "\n*** PCH/Modules Loaded:"; for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(), MEnd = ModuleMgr.end(); M != MEnd; ++M) (*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 (ModuleConstIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) { if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) { 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.ExternalSource = this; // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I], PreloadedDecls[I]->getDeclName()); } PreloadedDecls.clear(); // Load the offsets of the declarations that Sema references. // They will be lazily deserialized when needed. if (!SemaDeclRefs.empty()) { assert(SemaDeclRefs.size() == 2 && "More decl refs than expected!"); if (!SemaObj->StdNamespace) SemaObj->StdNamespace = SemaDeclRefs[0]; if (!SemaObj->StdBadAlloc) SemaObj->StdBadAlloc = SemaDeclRefs[1]; } if (!FPPragmaOptions.empty()) { assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS"); SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0]; } if (!OpenCLExtensions.empty()) { unsigned I = 0; #define OPENCLEXT(nm) SemaObj->OpenCLFeatures.nm = OpenCLExtensions[I++]; #include "clang/Basic/OpenCLExtensions.def" assert(OpenCLExtensions.size() == I && "Wrong number of OPENCL_EXTENSIONS"); } } IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) { IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart), /*PriorGeneration=*/0); ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); 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; public: explicit ASTIdentifierIterator(const ASTReader &Reader); virtual StringRef Next(); }; } ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader) : Reader(Reader), Index(Reader.ModuleMgr.size() - 1) { ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].IdentifierLookupTable; Current = IdTable->key_begin(); End = IdTable->key_end(); } StringRef ASTIdentifierIterator::Next() { while (Current == End) { // If we have exhausted all of our AST files, we're done. if (Index == 0) return StringRef(); --Index; ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index]. IdentifierLookupTable; Current = IdTable->key_begin(); End = IdTable->key_end(); } // We have any identifiers remaining in the current AST file; return // the next one. std::pair Key = *Current; ++Current; return StringRef(Key.first, Key.second); } IdentifierIterator *ASTReader::getIdentifiers() const { return new ASTIdentifierIterator(*this); } namespace clang { namespace serialization { class ReadMethodPoolVisitor { ASTReader &Reader; Selector Sel; unsigned PriorGeneration; llvm::SmallVector InstanceMethods; llvm::SmallVector FactoryMethods; public: ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, unsigned PriorGeneration) : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) { } static bool visit(ModuleFile &M, void *UserData) { ReadMethodPoolVisitor *This = static_cast(UserData); if (!M.SelectorLookupTable) return false; // If we've already searched this module file, skip it now. if (M.Generation <= This->PriorGeneration) return true; ASTSelectorLookupTable *PoolTable = (ASTSelectorLookupTable*)M.SelectorLookupTable; ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel); if (Pos == PoolTable->end()) return false; ++This->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? ++This->Reader.NumMethodPoolEntriesRead; ASTSelectorLookupTrait::data_type Data = *Pos; if (This->Reader.DeserializationListener) This->Reader.DeserializationListener->SelectorRead(Data.ID, This->Sel); This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); 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; } }; } } // end namespace clang::serialization /// \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 = CurrentGeneration; // Search for methods defined with this selector. ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration); ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor); if (Visitor.getInstanceMethods().empty() && Visitor.getFactoryMethods().empty()) { ++NumMethodPoolMisses; return; } if (!getSema()) return; Sema &S = *getSema(); Sema::GlobalMethodPool::iterator Pos = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first; addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first); addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); } 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::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::ReadDynamicClasses(SmallVectorImpl &Decls) { for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { CXXRecordDecl *D = dyn_cast_or_null(GetDecl(DynamicClasses[I])); if (D) Decls.push_back(D); } DynamicClasses.clear(); } void ASTReader::ReadLocallyScopedExternalDecls(SmallVectorImpl &Decls) { for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) { NamedDecl *D = dyn_cast_or_null(GetDecl(LocallyScopedExternalDecls[I])); if (D) Decls.push_back(D); } LocallyScopedExternalDecls.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::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 Nonrecursive should be true to indicate that the caller knows that /// this call is non-recursive, and therefore the globally-visible declarations /// will not be placed onto the pending queue. void ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, const SmallVectorImpl &DeclIDs, bool Nonrecursive) { if (NumCurrentElementsDeserializing && !Nonrecursive) { PendingIdentifierInfos.push_back(PendingIdentifierInfo()); PendingIdentifierInfo &PII = PendingIdentifierInfos.back(); PII.II = II; PII.DeclIDs.append(DeclIDs.begin(), DeclIDs.end()); return; } for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) { NamedDecl *D = cast(GetDecl(DeclIDs[I])); if (SemaObj) { // 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. SemaObj->pushExternalDeclIntoScope(D, II); } else { // 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. PreloadedDecls.push_back(D); } } } IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) { if (ID == 0) return 0; if (IdentifiersLoaded.empty()) { Error("no identifier table in AST file"); return 0; } 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; IdentifiersLoaded[ID] = &PP.getIdentifierTable().get(StringRef(Str, StrLen)); if (DeserializationListener) DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]); } 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; 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; } bool ASTReader::ReadSLocEntry(int ID) { return ReadSLocEntryRecord(ID) != Success; } serialization::SubmoduleID ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) { if (LocalID < NUM_PREDEF_SUBMODULE_IDS) return LocalID; ContinuousRangeMap::iterator I = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS); assert(I != M.SubmoduleRemap.end() && "Invalid index into identifier 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 0; } if (GlobalID > SubmodulesLoaded.size()) { Error("submodule ID out of range in AST file"); return 0; } return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS]; } 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() == 0) { // 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; ContinuousRangeMap::iterator I = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS); assert(I != M.SelectorRemap.end() && "Invalid index into identifier 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::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: 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) { 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: return TemplateArgument(ReadDecl(F, Record, Idx)); case TemplateArgument::Integral: { llvm::APSInt Value = ReadAPSInt(Record, Idx); QualType T = readType(F, Record, Idx); return TemplateArgument(Value, T); } case TemplateArgument::Template: return TemplateArgument(ReadTemplateName(F, Record, Idx)); case TemplateArgument::TemplateExpansion: { TemplateName Name = ReadTemplateName(F, Record, Idx); llvm::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(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)); TemplateParameterList* TemplateParams = TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, Params.data(), Params.size(), RAngleLoc); return TemplateParams; } void ASTReader:: ReadTemplateArgumentList(SmallVector &TemplArgs, ModuleFile &F, const RecordData &Record, unsigned &Idx) { unsigned NumTemplateArgs = Record[Idx++]; TemplArgs.reserve(NumTemplateArgs); while (NumTemplateArgs--) TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx)); } /// \brief Read a UnresolvedSet structure. void ASTReader::ReadUnresolvedSet(ModuleFile &F, UnresolvedSetImpl &Set, const RecordData &Record, unsigned &Idx) { unsigned NumDecls = Record[Idx++]; while (NumDecls--) { NamedDecl *D = ReadDeclAs(F, Record, Idx); AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; Set.addDecl(D, 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; } std::pair ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, unsigned &Idx) { CXXCtorInitializer **CtorInitializers = 0; unsigned NumInitializers = Record[Idx++]; if (NumInitializers) { CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers]; for (unsigned i=0; i != NumInitializers; ++i) { TypeSourceInfo *TInfo = 0; bool IsBaseVirtual = false; FieldDecl *Member = 0; IndirectFieldDecl *IndirectMember = 0; 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); bool IsWritten = Record[Idx++]; unsigned SourceOrderOrNumArrayIndices; SmallVector Indices; if (IsWritten) { SourceOrderOrNumArrayIndices = Record[Idx++]; } else { SourceOrderOrNumArrayIndices = Record[Idx++]; Indices.reserve(SourceOrderOrNumArrayIndices); for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i) Indices.push_back(ReadDeclAs(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 (IsWritten) { if (Member) BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc); else BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc); } else { BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc, Indices.data(), Indices.size()); } if (IsWritten) BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices); CtorInitializers[i] = BOMInit; } } return std::make_pair(CtorInitializers, NumInitializers); } NestedNameSpecifier * ASTReader::ReadNestedNameSpecifier(ModuleFile &F, const RecordData &Record, unsigned &Idx) { unsigned N = Record[Idx++]; NestedNameSpecifier *NNS = 0, *Prev = 0; 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 0; 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; } } 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; } } } 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, unsigned &Idx) { return llvm::APFloat(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; } 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) { return Diag(SourceLocation(), DiagID); } DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) { 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(SwitchCaseStmts[ID] == 0 && "Already have a SwitchCase with this ID"); SwitchCaseStmts[ID] = SC; } /// \brief Retrieve the switch-case statement with the given ID. SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) { assert(SwitchCaseStmts[ID] != 0 && "No SwitchCase with this ID"); return SwitchCaseStmts[ID]; } void ASTReader::ClearSwitchCaseIDs() { SwitchCaseStmts.clear(); } void ASTReader::finishPendingActions() { while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty()) { // If any identifiers with corresponding top-level declarations have // been loaded, load those declarations now. while (!PendingIdentifierInfos.empty()) { SetGloballyVisibleDecls(PendingIdentifierInfos.front().II, PendingIdentifierInfos.front().DeclIDs, true); PendingIdentifierInfos.pop_front(); } // Load pending declaration chains. for (unsigned I = 0; I != PendingDeclChains.size(); ++I) { loadPendingDeclChain(PendingDeclChains[I]); PendingDeclChainsKnown.erase(PendingDeclChains[I]); } PendingDeclChains.clear(); } // 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 (llvm::SmallPtrSet::iterator D = PendingDefinitions.begin(), DEnd = PendingDefinitions.end(); D != DEnd; ++D) { if (TagDecl *TD = dyn_cast(*D)) { if (const TagType *TagT = dyn_cast(TD->TypeForDecl)) { // Make sure that the TagType points at the definition. const_cast(TagT)->decl = TD; } if (CXXRecordDecl *RD = dyn_cast(*D)) { for (CXXRecordDecl::redecl_iterator R = RD->redecls_begin(), REnd = RD->redecls_end(); R != REnd; ++R) cast(*R)->DefinitionData = RD->DefinitionData; } continue; } if (ObjCInterfaceDecl *ID = dyn_cast(*D)) { // Make sure that the ObjCInterfaceType points at the definition. const_cast(cast(ID->TypeForDecl)) ->Decl = ID; for (ObjCInterfaceDecl::redecl_iterator R = ID->redecls_begin(), REnd = ID->redecls_end(); R != REnd; ++R) R->Data = ID->Data; continue; } if (ObjCProtocolDecl *PD = dyn_cast(*D)) { for (ObjCProtocolDecl::redecl_iterator R = PD->redecls_begin(), REnd = PD->redecls_end(); R != REnd; ++R) R->Data = PD->Data; continue; } RedeclarableTemplateDecl *RTD = cast(*D)->getCanonicalDecl(); for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(), REnd = RTD->redecls_end(); R != REnd; ++R) R->Common = RTD->Common; } PendingDefinitions.clear(); } 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 && Consumer && !PassingDeclsToConsumer) { // Guard variable to avoid recursively redoing the process of passing // decls to consumer. SaveAndRestore GuardPassingDeclsToConsumer(PassingDeclsToConsumer, true); while (!InterestingDecls.empty()) { // We are not in recursive loading, so it's safe to pass the "interesting" // decls to the consumer. Decl *D = InterestingDecls.front(); InterestingDecls.pop_front(); PassInterestingDeclToConsumer(D); } } } ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot, bool DisableValidation, bool DisableStatCache, bool AllowASTWithCompilerErrors) : Listener(new PCHValidator(PP, *this)), DeserializationListener(0), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context), Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()), RelocatablePCH(false), isysroot(isysroot), DisableValidation(DisableValidation), DisableStatCache(DisableStatCache), AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), CurrentGeneration(0), NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0), TotalNumSLocEntries(0), NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0), NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0), NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0), NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0), TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0), PassingDeclsToConsumer(false), NumCXXBaseSpecifiersLoaded(0) { SourceMgr.setExternalSLocEntrySource(this); } ASTReader::~ASTReader() { for (DeclContextVisibleUpdatesPending::iterator I = PendingVisibleUpdates.begin(), E = PendingVisibleUpdates.end(); I != E; ++I) { for (DeclContextVisibleUpdates::iterator J = I->second.begin(), F = I->second.end(); J != F; ++J) delete J->first; } } Index: vendor/clang/dist/lib/Serialization/ASTWriter.cpp =================================================================== --- vendor/clang/dist/lib/Serialization/ASTWriter.cpp (revision 235808) +++ vendor/clang/dist/lib/Serialization/ASTWriter.cpp (revision 235809) @@ -1,4549 +1,4552 @@ //===--- ASTWriter.cpp - AST File Writer ----------------------------------===// // // 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 ASTWriter class, which writes AST files. // //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" #include "ASTCommon.h" #include "clang/Sema/Sema.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Serialization/ASTReader.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/OnDiskHashTable.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/Basic/VersionTuple.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include #include #include #include using namespace clang; using namespace clang::serialization; template static StringRef data(const std::vector &v) { if (v.empty()) return StringRef(); return StringRef(reinterpret_cast(&v[0]), sizeof(T) * v.size()); } template static StringRef data(const SmallVectorImpl &v) { return StringRef(reinterpret_cast(v.data()), sizeof(T) * v.size()); } //===----------------------------------------------------------------------===// // Type serialization //===----------------------------------------------------------------------===// namespace { class ASTTypeWriter { ASTWriter &Writer; ASTWriter::RecordDataImpl &Record; public: /// \brief Type code that corresponds to the record generated. TypeCode Code; ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record) : Writer(Writer), Record(Record), Code(TYPE_EXT_QUAL) { } void VisitArrayType(const ArrayType *T); void VisitFunctionType(const FunctionType *T); void VisitTagType(const TagType *T); #define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T); #define ABSTRACT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" }; } void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) { llvm_unreachable("Built-in types are never serialized"); } void ASTTypeWriter::VisitComplexType(const ComplexType *T) { Writer.AddTypeRef(T->getElementType(), Record); Code = TYPE_COMPLEX; } void ASTTypeWriter::VisitPointerType(const PointerType *T) { Writer.AddTypeRef(T->getPointeeType(), Record); Code = TYPE_POINTER; } void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) { Writer.AddTypeRef(T->getPointeeType(), Record); Code = TYPE_BLOCK_POINTER; } void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) { Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record); Record.push_back(T->isSpelledAsLValue()); Code = TYPE_LVALUE_REFERENCE; } void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) { Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record); Code = TYPE_RVALUE_REFERENCE; } void ASTTypeWriter::VisitMemberPointerType(const MemberPointerType *T) { Writer.AddTypeRef(T->getPointeeType(), Record); Writer.AddTypeRef(QualType(T->getClass(), 0), Record); Code = TYPE_MEMBER_POINTER; } void ASTTypeWriter::VisitArrayType(const ArrayType *T) { Writer.AddTypeRef(T->getElementType(), Record); Record.push_back(T->getSizeModifier()); // FIXME: stable values Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values } void ASTTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) { VisitArrayType(T); Writer.AddAPInt(T->getSize(), Record); Code = TYPE_CONSTANT_ARRAY; } void ASTTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) { VisitArrayType(T); Code = TYPE_INCOMPLETE_ARRAY; } void ASTTypeWriter::VisitVariableArrayType(const VariableArrayType *T) { VisitArrayType(T); Writer.AddSourceLocation(T->getLBracketLoc(), Record); Writer.AddSourceLocation(T->getRBracketLoc(), Record); Writer.AddStmt(T->getSizeExpr()); Code = TYPE_VARIABLE_ARRAY; } void ASTTypeWriter::VisitVectorType(const VectorType *T) { Writer.AddTypeRef(T->getElementType(), Record); Record.push_back(T->getNumElements()); Record.push_back(T->getVectorKind()); Code = TYPE_VECTOR; } void ASTTypeWriter::VisitExtVectorType(const ExtVectorType *T) { VisitVectorType(T); Code = TYPE_EXT_VECTOR; } void ASTTypeWriter::VisitFunctionType(const FunctionType *T) { Writer.AddTypeRef(T->getResultType(), Record); FunctionType::ExtInfo C = T->getExtInfo(); Record.push_back(C.getNoReturn()); Record.push_back(C.getHasRegParm()); Record.push_back(C.getRegParm()); // FIXME: need to stabilize encoding of calling convention... Record.push_back(C.getCC()); Record.push_back(C.getProducesResult()); } void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { VisitFunctionType(T); Code = TYPE_FUNCTION_NO_PROTO; } void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { VisitFunctionType(T); Record.push_back(T->getNumArgs()); for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I) Writer.AddTypeRef(T->getArgType(I), Record); Record.push_back(T->isVariadic()); Record.push_back(T->hasTrailingReturn()); Record.push_back(T->getTypeQuals()); Record.push_back(static_cast(T->getRefQualifier())); Record.push_back(T->getExceptionSpecType()); if (T->getExceptionSpecType() == EST_Dynamic) { Record.push_back(T->getNumExceptions()); for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) Writer.AddTypeRef(T->getExceptionType(I), Record); } else if (T->getExceptionSpecType() == EST_ComputedNoexcept) { Writer.AddStmt(T->getNoexceptExpr()); + } else if (T->getExceptionSpecType() == EST_Uninstantiated) { + Writer.AddDeclRef(T->getExceptionSpecDecl(), Record); + Writer.AddDeclRef(T->getExceptionSpecTemplate(), Record); } Code = TYPE_FUNCTION_PROTO; } void ASTTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { Writer.AddDeclRef(T->getDecl(), Record); Code = TYPE_UNRESOLVED_USING; } void ASTTypeWriter::VisitTypedefType(const TypedefType *T) { Writer.AddDeclRef(T->getDecl(), Record); assert(!T->isCanonicalUnqualified() && "Invalid typedef ?"); Writer.AddTypeRef(T->getCanonicalTypeInternal(), Record); Code = TYPE_TYPEDEF; } void ASTTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) { Writer.AddStmt(T->getUnderlyingExpr()); Code = TYPE_TYPEOF_EXPR; } void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) { Writer.AddTypeRef(T->getUnderlyingType(), Record); Code = TYPE_TYPEOF; } void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) { Writer.AddTypeRef(T->getUnderlyingType(), Record); Writer.AddStmt(T->getUnderlyingExpr()); Code = TYPE_DECLTYPE; } void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { Writer.AddTypeRef(T->getBaseType(), Record); Writer.AddTypeRef(T->getUnderlyingType(), Record); Record.push_back(T->getUTTKind()); Code = TYPE_UNARY_TRANSFORM; } void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); Code = TYPE_AUTO; } void ASTTypeWriter::VisitTagType(const TagType *T) { Record.push_back(T->isDependentType()); Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record); assert(!T->isBeingDefined() && "Cannot serialize in the middle of a type definition"); } void ASTTypeWriter::VisitRecordType(const RecordType *T) { VisitTagType(T); Code = TYPE_RECORD; } void ASTTypeWriter::VisitEnumType(const EnumType *T) { VisitTagType(T); Code = TYPE_ENUM; } void ASTTypeWriter::VisitAttributedType(const AttributedType *T) { Writer.AddTypeRef(T->getModifiedType(), Record); Writer.AddTypeRef(T->getEquivalentType(), Record); Record.push_back(T->getAttrKind()); Code = TYPE_ATTRIBUTED; } void ASTTypeWriter::VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *T) { Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record); Writer.AddTypeRef(T->getReplacementType(), Record); Code = TYPE_SUBST_TEMPLATE_TYPE_PARM; } void ASTTypeWriter::VisitSubstTemplateTypeParmPackType( const SubstTemplateTypeParmPackType *T) { Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record); Writer.AddTemplateArgument(T->getArgumentPack(), Record); Code = TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK; } void ASTTypeWriter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { Record.push_back(T->isDependentType()); Writer.AddTemplateName(T->getTemplateName(), Record); Record.push_back(T->getNumArgs()); for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end(); ArgI != ArgE; ++ArgI) Writer.AddTemplateArgument(*ArgI, Record); Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() : T->isCanonicalUnqualified() ? QualType() : T->getCanonicalTypeInternal(), Record); Code = TYPE_TEMPLATE_SPECIALIZATION; } void ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) { VisitArrayType(T); Writer.AddStmt(T->getSizeExpr()); Writer.AddSourceRange(T->getBracketsRange(), Record); Code = TYPE_DEPENDENT_SIZED_ARRAY; } void ASTTypeWriter::VisitDependentSizedExtVectorType( const DependentSizedExtVectorType *T) { // FIXME: Serialize this type (C++ only) llvm_unreachable("Cannot serialize dependent sized extended vector types"); } void ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { Record.push_back(T->getDepth()); Record.push_back(T->getIndex()); Record.push_back(T->isParameterPack()); Writer.AddDeclRef(T->getDecl(), Record); Code = TYPE_TEMPLATE_TYPE_PARM; } void ASTTypeWriter::VisitDependentNameType(const DependentNameType *T) { Record.push_back(T->getKeyword()); Writer.AddNestedNameSpecifier(T->getQualifier(), Record); Writer.AddIdentifierRef(T->getIdentifier(), Record); Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType() : T->getCanonicalTypeInternal(), Record); Code = TYPE_DEPENDENT_NAME; } void ASTTypeWriter::VisitDependentTemplateSpecializationType( const DependentTemplateSpecializationType *T) { Record.push_back(T->getKeyword()); Writer.AddNestedNameSpecifier(T->getQualifier(), Record); Writer.AddIdentifierRef(T->getIdentifier(), Record); Record.push_back(T->getNumArgs()); for (DependentTemplateSpecializationType::iterator I = T->begin(), E = T->end(); I != E; ++I) Writer.AddTemplateArgument(*I, Record); Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION; } void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) { Writer.AddTypeRef(T->getPattern(), Record); if (llvm::Optional NumExpansions = T->getNumExpansions()) Record.push_back(*NumExpansions + 1); else Record.push_back(0); Code = TYPE_PACK_EXPANSION; } void ASTTypeWriter::VisitParenType(const ParenType *T) { Writer.AddTypeRef(T->getInnerType(), Record); Code = TYPE_PAREN; } void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) { Record.push_back(T->getKeyword()); Writer.AddNestedNameSpecifier(T->getQualifier(), Record); Writer.AddTypeRef(T->getNamedType(), Record); Code = TYPE_ELABORATED; } void ASTTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record); Writer.AddTypeRef(T->getInjectedSpecializationType(), Record); Code = TYPE_INJECTED_CLASS_NAME; } void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record); Code = TYPE_OBJC_INTERFACE; } void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { Writer.AddTypeRef(T->getBaseType(), Record); Record.push_back(T->getNumProtocols()); for (ObjCObjectType::qual_iterator I = T->qual_begin(), E = T->qual_end(); I != E; ++I) Writer.AddDeclRef(*I, Record); Code = TYPE_OBJC_OBJECT; } void ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { Writer.AddTypeRef(T->getPointeeType(), Record); Code = TYPE_OBJC_OBJECT_POINTER; } void ASTTypeWriter::VisitAtomicType(const AtomicType *T) { Writer.AddTypeRef(T->getValueType(), Record); Code = TYPE_ATOMIC; } namespace { class TypeLocWriter : public TypeLocVisitor { ASTWriter &Writer; ASTWriter::RecordDataImpl &Record; public: TypeLocWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record) : Writer(Writer), Record(Record) { } #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); #include "clang/AST/TypeLocNodes.def" void VisitArrayTypeLoc(ArrayTypeLoc TyLoc); void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc); }; } void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do } void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { Writer.AddSourceLocation(TL.getBuiltinLoc(), Record); if (TL.needsExtraLocalData()) { Record.push_back(TL.getWrittenTypeSpec()); Record.push_back(TL.getWrittenSignSpec()); Record.push_back(TL.getWrittenWidthSpec()); Record.push_back(TL.hasModeAttr()); } } void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { Writer.AddSourceLocation(TL.getStarLoc(), Record); } void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { Writer.AddSourceLocation(TL.getCaretLoc(), Record); } void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { Writer.AddSourceLocation(TL.getAmpLoc(), Record); } void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record); } void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { Writer.AddSourceLocation(TL.getStarLoc(), Record); Writer.AddTypeSourceInfo(TL.getClassTInfo(), Record); } void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) { Writer.AddSourceLocation(TL.getLBracketLoc(), Record); Writer.AddSourceLocation(TL.getRBracketLoc(), Record); Record.push_back(TL.getSizeExpr() ? 1 : 0); if (TL.getSizeExpr()) Writer.AddStmt(TL.getSizeExpr()); } void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocWriter::VisitDependentSizedArrayTypeLoc( DependentSizedArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record); Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record); Record.push_back(TL.getTrailingReturn()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) Writer.AddDeclRef(TL.getArg(i), Record); } void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { Writer.AddSourceLocation(TL.getTypeofLoc(), Record); Writer.AddSourceLocation(TL.getLParenLoc(), Record); Writer.AddSourceLocation(TL.getRParenLoc(), Record); } void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { Writer.AddSourceLocation(TL.getTypeofLoc(), Record); Writer.AddSourceLocation(TL.getLParenLoc(), Record); Writer.AddSourceLocation(TL.getRParenLoc(), Record); Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record); } void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { Writer.AddSourceLocation(TL.getKWLoc(), Record); Writer.AddSourceLocation(TL.getLParenLoc(), Record); Writer.AddSourceLocation(TL.getRParenLoc(), Record); Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record); } void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) { Writer.AddSourceLocation(TL.getAttrNameLoc(), Record); if (TL.hasAttrOperand()) { SourceRange range = TL.getAttrOperandParensRange(); Writer.AddSourceLocation(range.getBegin(), Record); Writer.AddSourceLocation(range.getEnd(), Record); } if (TL.hasAttrExprOperand()) { Expr *operand = TL.getAttrExprOperand(); Record.push_back(operand ? 1 : 0); if (operand) Writer.AddStmt(operand); } else if (TL.hasAttrEnumOperand()) { Writer.AddSourceLocation(TL.getAttrEnumOperandLoc(), Record); } } void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( SubstTemplateTypeParmTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc( SubstTemplateTypeParmPackTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record); Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record); Writer.AddSourceLocation(TL.getLAngleLoc(), Record); Writer.AddSourceLocation(TL.getRAngleLoc(), Record); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(), TL.getArgLoc(i).getLocInfo(), Record); } void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) { Writer.AddSourceLocation(TL.getLParenLoc(), Record); Writer.AddSourceLocation(TL.getRParenLoc(), Record); } void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record); Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record); } void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record); Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record); Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record); Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record); Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record); Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record); Writer.AddSourceLocation(TL.getLAngleLoc(), Record); Writer.AddSourceLocation(TL.getRAngleLoc(), Record); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(), TL.getArgLoc(I).getLocInfo(), Record); } void TypeLocWriter::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { Writer.AddSourceLocation(TL.getEllipsisLoc(), Record); } void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { Record.push_back(TL.hasBaseTypeAsWritten()); Writer.AddSourceLocation(TL.getLAngleLoc(), Record); Writer.AddSourceLocation(TL.getRAngleLoc(), Record); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); } void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { Writer.AddSourceLocation(TL.getStarLoc(), Record); } void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) { Writer.AddSourceLocation(TL.getKWLoc(), Record); Writer.AddSourceLocation(TL.getLParenLoc(), Record); Writer.AddSourceLocation(TL.getRParenLoc(), Record); } //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// static void EmitBlockID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, ASTWriter::RecordDataImpl &Record) { Record.clear(); Record.push_back(ID); Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); // Emit the block name if present. if (Name == 0 || Name[0] == 0) return; Record.clear(); while (*Name) Record.push_back(*Name++); Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); } static void EmitRecordID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, ASTWriter::RecordDataImpl &Record) { Record.clear(); Record.push_back(ID); while (*Name) Record.push_back(*Name++); Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); } static void AddStmtsExprs(llvm::BitstreamWriter &Stream, ASTWriter::RecordDataImpl &Record) { #define RECORD(X) EmitRecordID(X, #X, Stream, Record) RECORD(STMT_STOP); RECORD(STMT_NULL_PTR); RECORD(STMT_NULL); RECORD(STMT_COMPOUND); RECORD(STMT_CASE); RECORD(STMT_DEFAULT); RECORD(STMT_LABEL); RECORD(STMT_ATTRIBUTED); RECORD(STMT_IF); RECORD(STMT_SWITCH); RECORD(STMT_WHILE); RECORD(STMT_DO); RECORD(STMT_FOR); RECORD(STMT_GOTO); RECORD(STMT_INDIRECT_GOTO); RECORD(STMT_CONTINUE); RECORD(STMT_BREAK); RECORD(STMT_RETURN); RECORD(STMT_DECL); RECORD(STMT_ASM); RECORD(EXPR_PREDEFINED); RECORD(EXPR_DECL_REF); RECORD(EXPR_INTEGER_LITERAL); RECORD(EXPR_FLOATING_LITERAL); RECORD(EXPR_IMAGINARY_LITERAL); RECORD(EXPR_STRING_LITERAL); RECORD(EXPR_CHARACTER_LITERAL); RECORD(EXPR_PAREN); RECORD(EXPR_UNARY_OPERATOR); RECORD(EXPR_SIZEOF_ALIGN_OF); RECORD(EXPR_ARRAY_SUBSCRIPT); RECORD(EXPR_CALL); RECORD(EXPR_MEMBER); RECORD(EXPR_BINARY_OPERATOR); RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR); RECORD(EXPR_CONDITIONAL_OPERATOR); RECORD(EXPR_IMPLICIT_CAST); RECORD(EXPR_CSTYLE_CAST); RECORD(EXPR_COMPOUND_LITERAL); RECORD(EXPR_EXT_VECTOR_ELEMENT); RECORD(EXPR_INIT_LIST); RECORD(EXPR_DESIGNATED_INIT); RECORD(EXPR_IMPLICIT_VALUE_INIT); RECORD(EXPR_VA_ARG); RECORD(EXPR_ADDR_LABEL); RECORD(EXPR_STMT); RECORD(EXPR_CHOOSE); RECORD(EXPR_GNU_NULL); RECORD(EXPR_SHUFFLE_VECTOR); RECORD(EXPR_BLOCK); RECORD(EXPR_GENERIC_SELECTION); RECORD(EXPR_OBJC_STRING_LITERAL); RECORD(EXPR_OBJC_NUMERIC_LITERAL); RECORD(EXPR_OBJC_ARRAY_LITERAL); RECORD(EXPR_OBJC_DICTIONARY_LITERAL); RECORD(EXPR_OBJC_ENCODE); RECORD(EXPR_OBJC_SELECTOR_EXPR); RECORD(EXPR_OBJC_PROTOCOL_EXPR); RECORD(EXPR_OBJC_IVAR_REF_EXPR); RECORD(EXPR_OBJC_PROPERTY_REF_EXPR); RECORD(EXPR_OBJC_KVC_REF_EXPR); RECORD(EXPR_OBJC_MESSAGE_EXPR); RECORD(STMT_OBJC_FOR_COLLECTION); RECORD(STMT_OBJC_CATCH); RECORD(STMT_OBJC_FINALLY); RECORD(STMT_OBJC_AT_TRY); RECORD(STMT_OBJC_AT_SYNCHRONIZED); RECORD(STMT_OBJC_AT_THROW); RECORD(EXPR_OBJC_BOOL_LITERAL); RECORD(EXPR_CXX_OPERATOR_CALL); RECORD(EXPR_CXX_CONSTRUCT); RECORD(EXPR_CXX_STATIC_CAST); RECORD(EXPR_CXX_DYNAMIC_CAST); RECORD(EXPR_CXX_REINTERPRET_CAST); RECORD(EXPR_CXX_CONST_CAST); RECORD(EXPR_CXX_FUNCTIONAL_CAST); RECORD(EXPR_USER_DEFINED_LITERAL); RECORD(EXPR_CXX_BOOL_LITERAL); RECORD(EXPR_CXX_NULL_PTR_LITERAL); RECORD(EXPR_CXX_TYPEID_EXPR); RECORD(EXPR_CXX_TYPEID_TYPE); RECORD(EXPR_CXX_UUIDOF_EXPR); RECORD(EXPR_CXX_UUIDOF_TYPE); RECORD(EXPR_CXX_THIS); RECORD(EXPR_CXX_THROW); RECORD(EXPR_CXX_DEFAULT_ARG); RECORD(EXPR_CXX_BIND_TEMPORARY); RECORD(EXPR_CXX_SCALAR_VALUE_INIT); RECORD(EXPR_CXX_NEW); RECORD(EXPR_CXX_DELETE); RECORD(EXPR_CXX_PSEUDO_DESTRUCTOR); RECORD(EXPR_EXPR_WITH_CLEANUPS); RECORD(EXPR_CXX_DEPENDENT_SCOPE_MEMBER); RECORD(EXPR_CXX_DEPENDENT_SCOPE_DECL_REF); RECORD(EXPR_CXX_UNRESOLVED_CONSTRUCT); RECORD(EXPR_CXX_UNRESOLVED_MEMBER); RECORD(EXPR_CXX_UNRESOLVED_LOOKUP); RECORD(EXPR_CXX_UNARY_TYPE_TRAIT); RECORD(EXPR_CXX_NOEXCEPT); RECORD(EXPR_OPAQUE_VALUE); RECORD(EXPR_BINARY_TYPE_TRAIT); RECORD(EXPR_PACK_EXPANSION); RECORD(EXPR_SIZEOF_PACK); RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK); RECORD(EXPR_CUDA_KERNEL_CALL); #undef RECORD } void ASTWriter::WriteBlockInfoBlock() { RecordData Record; Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3); #define BLOCK(X) EmitBlockID(X ## _ID, #X, Stream, Record) #define RECORD(X) EmitRecordID(X, #X, Stream, Record) // AST Top-Level Block. BLOCK(AST_BLOCK); RECORD(ORIGINAL_FILE_NAME); RECORD(ORIGINAL_FILE_ID); RECORD(TYPE_OFFSET); RECORD(DECL_OFFSET); RECORD(LANGUAGE_OPTIONS); RECORD(METADATA); RECORD(IDENTIFIER_OFFSET); RECORD(IDENTIFIER_TABLE); RECORD(EXTERNAL_DEFINITIONS); RECORD(SPECIAL_TYPES); RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); RECORD(UNUSED_FILESCOPED_DECLS); RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS); RECORD(SELECTOR_OFFSETS); RECORD(METHOD_POOL); RECORD(PP_COUNTER_VALUE); RECORD(SOURCE_LOCATION_OFFSETS); RECORD(SOURCE_LOCATION_PRELOADS); RECORD(STAT_CACHE); RECORD(EXT_VECTOR_DECLS); RECORD(VERSION_CONTROL_BRANCH_REVISION); RECORD(PPD_ENTITIES_OFFSETS); RECORD(IMPORTS); RECORD(REFERENCED_SELECTOR_POOL); RECORD(TU_UPDATE_LEXICAL); RECORD(LOCAL_REDECLARATIONS_MAP); RECORD(SEMA_DECL_REFS); RECORD(WEAK_UNDECLARED_IDENTIFIERS); RECORD(PENDING_IMPLICIT_INSTANTIATIONS); RECORD(DECL_REPLACEMENTS); RECORD(UPDATE_VISIBLE); RECORD(DECL_UPDATE_OFFSETS); RECORD(DECL_UPDATES); RECORD(CXX_BASE_SPECIFIER_OFFSETS); RECORD(DIAG_PRAGMA_MAPPINGS); RECORD(CUDA_SPECIAL_DECL_REFS); RECORD(HEADER_SEARCH_TABLE); RECORD(ORIGINAL_PCH_DIR); RECORD(FP_PRAGMA_OPTIONS); RECORD(OPENCL_EXTENSIONS); RECORD(DELEGATING_CTORS); RECORD(FILE_SOURCE_LOCATION_OFFSETS); RECORD(KNOWN_NAMESPACES); RECORD(MODULE_OFFSET_MAP); RECORD(SOURCE_MANAGER_LINE_TABLE); RECORD(OBJC_CATEGORIES_MAP); RECORD(FILE_SORTED_DECLS); RECORD(IMPORTED_MODULES); RECORD(MERGED_DECLARATIONS); RECORD(LOCAL_REDECLARATIONS); RECORD(OBJC_CATEGORIES); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); RECORD(SM_SLOC_FILE_ENTRY); RECORD(SM_SLOC_BUFFER_ENTRY); RECORD(SM_SLOC_BUFFER_BLOB); RECORD(SM_SLOC_EXPANSION_ENTRY); // Preprocessor Block. BLOCK(PREPROCESSOR_BLOCK); RECORD(PP_MACRO_OBJECT_LIKE); RECORD(PP_MACRO_FUNCTION_LIKE); RECORD(PP_TOKEN); // Decls and Types block. BLOCK(DECLTYPES_BLOCK); RECORD(TYPE_EXT_QUAL); RECORD(TYPE_COMPLEX); RECORD(TYPE_POINTER); RECORD(TYPE_BLOCK_POINTER); RECORD(TYPE_LVALUE_REFERENCE); RECORD(TYPE_RVALUE_REFERENCE); RECORD(TYPE_MEMBER_POINTER); RECORD(TYPE_CONSTANT_ARRAY); RECORD(TYPE_INCOMPLETE_ARRAY); RECORD(TYPE_VARIABLE_ARRAY); RECORD(TYPE_VECTOR); RECORD(TYPE_EXT_VECTOR); RECORD(TYPE_FUNCTION_PROTO); RECORD(TYPE_FUNCTION_NO_PROTO); RECORD(TYPE_TYPEDEF); RECORD(TYPE_TYPEOF_EXPR); RECORD(TYPE_TYPEOF); RECORD(TYPE_RECORD); RECORD(TYPE_ENUM); RECORD(TYPE_OBJC_INTERFACE); RECORD(TYPE_OBJC_OBJECT); RECORD(TYPE_OBJC_OBJECT_POINTER); RECORD(TYPE_DECLTYPE); RECORD(TYPE_ELABORATED); RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM); RECORD(TYPE_UNRESOLVED_USING); RECORD(TYPE_INJECTED_CLASS_NAME); RECORD(TYPE_OBJC_OBJECT); RECORD(TYPE_TEMPLATE_TYPE_PARM); RECORD(TYPE_TEMPLATE_SPECIALIZATION); RECORD(TYPE_DEPENDENT_NAME); RECORD(TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION); RECORD(TYPE_DEPENDENT_SIZED_ARRAY); RECORD(TYPE_PAREN); RECORD(TYPE_PACK_EXPANSION); RECORD(TYPE_ATTRIBUTED); RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK); RECORD(TYPE_ATOMIC); RECORD(DECL_TYPEDEF); RECORD(DECL_ENUM); RECORD(DECL_RECORD); RECORD(DECL_ENUM_CONSTANT); RECORD(DECL_FUNCTION); RECORD(DECL_OBJC_METHOD); RECORD(DECL_OBJC_INTERFACE); RECORD(DECL_OBJC_PROTOCOL); RECORD(DECL_OBJC_IVAR); RECORD(DECL_OBJC_AT_DEFS_FIELD); RECORD(DECL_OBJC_CATEGORY); RECORD(DECL_OBJC_CATEGORY_IMPL); RECORD(DECL_OBJC_IMPLEMENTATION); RECORD(DECL_OBJC_COMPATIBLE_ALIAS); RECORD(DECL_OBJC_PROPERTY); RECORD(DECL_OBJC_PROPERTY_IMPL); RECORD(DECL_FIELD); RECORD(DECL_VAR); RECORD(DECL_IMPLICIT_PARAM); RECORD(DECL_PARM_VAR); RECORD(DECL_FILE_SCOPE_ASM); RECORD(DECL_BLOCK); RECORD(DECL_CONTEXT_LEXICAL); RECORD(DECL_CONTEXT_VISIBLE); RECORD(DECL_NAMESPACE); RECORD(DECL_NAMESPACE_ALIAS); RECORD(DECL_USING); RECORD(DECL_USING_SHADOW); RECORD(DECL_USING_DIRECTIVE); RECORD(DECL_UNRESOLVED_USING_VALUE); RECORD(DECL_UNRESOLVED_USING_TYPENAME); RECORD(DECL_LINKAGE_SPEC); RECORD(DECL_CXX_RECORD); RECORD(DECL_CXX_METHOD); RECORD(DECL_CXX_CONSTRUCTOR); RECORD(DECL_CXX_DESTRUCTOR); RECORD(DECL_CXX_CONVERSION); RECORD(DECL_ACCESS_SPEC); RECORD(DECL_FRIEND); RECORD(DECL_FRIEND_TEMPLATE); RECORD(DECL_CLASS_TEMPLATE); RECORD(DECL_CLASS_TEMPLATE_SPECIALIZATION); RECORD(DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION); RECORD(DECL_FUNCTION_TEMPLATE); RECORD(DECL_TEMPLATE_TYPE_PARM); RECORD(DECL_NON_TYPE_TEMPLATE_PARM); RECORD(DECL_TEMPLATE_TEMPLATE_PARM); RECORD(DECL_STATIC_ASSERT); RECORD(DECL_CXX_BASE_SPECIFIERS); RECORD(DECL_INDIRECTFIELD); RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK); // Statements and Exprs can occur in the Decls and Types block. AddStmtsExprs(Stream, Record); BLOCK(PREPROCESSOR_DETAIL_BLOCK); RECORD(PPD_MACRO_EXPANSION); RECORD(PPD_MACRO_DEFINITION); RECORD(PPD_INCLUSION_DIRECTIVE); #undef RECORD #undef BLOCK Stream.ExitBlock(); } /// \brief Adjusts the given filename to only write out the portion of the /// filename that is not part of the system root directory. /// /// \param Filename the file name to adjust. /// /// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and /// the returned filename will be adjusted by this system root. /// /// \returns either the original filename (if it needs no adjustment) or the /// adjusted filename (which points into the @p Filename parameter). static const char * adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) { assert(Filename && "No file name to adjust?"); if (isysroot.empty()) return Filename; // Verify that the filename and the system root have the same prefix. unsigned Pos = 0; for (; Filename[Pos] && Pos < isysroot.size(); ++Pos) if (Filename[Pos] != isysroot[Pos]) return Filename; // Prefixes don't match. // We hit the end of the filename before we hit the end of the system root. if (!Filename[Pos]) return Filename; // If the file name has a '/' at the current position, skip over the '/'. // We distinguish sysroot-based includes from absolute includes by the // absence of '/' at the beginning of sysroot-based includes. if (Filename[Pos] == '/') ++Pos; return Filename + Pos; } /// \brief Write the AST metadata (e.g., i686-apple-darwin9). void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot, const std::string &OutputFile) { using namespace llvm; // Metadata const TargetInfo &Target = Context.getTargetInfo(); BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev(); MetaAbbrev->Add(BitCodeAbbrevOp(METADATA)); MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST major MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST minor MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Has errors MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev); RecordData Record; Record.push_back(METADATA); Record.push_back(VERSION_MAJOR); Record.push_back(VERSION_MINOR); Record.push_back(CLANG_VERSION_MAJOR); Record.push_back(CLANG_VERSION_MINOR); Record.push_back(!isysroot.empty()); Record.push_back(ASTHasCompilerErrors); const std::string &Triple = Target.getTriple().getTriple(); Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple); if (Chain) { serialization::ModuleManager &Mgr = Chain->getModuleManager(); llvm::SmallVector ModulePaths; Record.clear(); for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end(); M != MEnd; ++M) { // Skip modules that weren't directly imported. if (!(*M)->isDirectlyImported()) continue; Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding // FIXME: Write import location, once it matters. // FIXME: This writes the absolute path for AST files we depend on. const std::string &FileName = (*M)->FileName; Record.push_back(FileName.size()); Record.append(FileName.begin(), FileName.end()); } Stream.EmitRecord(IMPORTS, Record); } // Original file name and file ID SourceManager &SM = Context.getSourceManager(); if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev(); FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE_NAME)); FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev); SmallString<128> MainFilePath(MainFile->getName()); llvm::sys::fs::make_absolute(MainFilePath); const char *MainFileNameStr = MainFilePath.c_str(); MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr, isysroot); RecordData Record; Record.push_back(ORIGINAL_FILE_NAME); Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); Record.clear(); Record.push_back(SM.getMainFileID().getOpaqueValue()); Stream.EmitRecord(ORIGINAL_FILE_ID, Record); } // Original PCH directory if (!OutputFile.empty() && OutputFile != "-") { BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); SmallString<128> OutputPath(OutputFile); llvm::sys::fs::make_absolute(OutputPath); StringRef origDir = llvm::sys::path::parent_path(OutputPath); RecordData Record; Record.push_back(ORIGINAL_PCH_DIR); Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir); } // Repository branch/version information. BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev(); RepoAbbrev->Add(BitCodeAbbrevOp(VERSION_CONTROL_BRANCH_REVISION)); RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev); Record.clear(); Record.push_back(VERSION_CONTROL_BRANCH_REVISION); Stream.EmitRecordWithBlob(RepoAbbrevCode, Record, getClangFullRepositoryVersion()); } /// \brief Write the LangOptions structure. void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) { RecordData Record; #define LANGOPT(Name, Bits, Default, Description) \ Record.push_back(LangOpts.Name); #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ Record.push_back(static_cast(LangOpts.get##Name())); #include "clang/Basic/LangOptions.def" Record.push_back(LangOpts.CurrentModule.size()); Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end()); Stream.EmitRecord(LANGUAGE_OPTIONS, Record); } //===----------------------------------------------------------------------===// // stat cache Serialization //===----------------------------------------------------------------------===// namespace { // Trait used for the on-disk hash table of stat cache results. class ASTStatCacheTrait { public: typedef const char * key_type; typedef key_type key_type_ref; typedef struct stat data_type; typedef const data_type &data_type_ref; static unsigned ComputeHash(const char *path) { return llvm::HashString(path); } std::pair EmitKeyDataLength(raw_ostream& Out, const char *path, data_type_ref Data) { unsigned StrLen = strlen(path); clang::io::Emit16(Out, StrLen); unsigned DataLen = 4 + 4 + 2 + 8 + 8; clang::io::Emit8(Out, DataLen); return std::make_pair(StrLen + 1, DataLen); } void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) { Out.write(path, KeyLen); } void EmitData(raw_ostream &Out, key_type_ref, data_type_ref Data, unsigned DataLen) { using namespace clang::io; uint64_t Start = Out.tell(); (void)Start; Emit32(Out, (uint32_t) Data.st_ino); Emit32(Out, (uint32_t) Data.st_dev); Emit16(Out, (uint16_t) Data.st_mode); Emit64(Out, (uint64_t) Data.st_mtime); Emit64(Out, (uint64_t) Data.st_size); assert(Out.tell() - Start == DataLen && "Wrong data length"); } }; } // end anonymous namespace /// \brief Write the stat() system call cache to the AST file. void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) { // Build the on-disk hash table containing information about every // stat() call. OnDiskChainedHashTableGenerator Generator; unsigned NumStatEntries = 0; for (MemorizeStatCalls::iterator Stat = StatCalls.begin(), StatEnd = StatCalls.end(); Stat != StatEnd; ++Stat, ++NumStatEntries) { StringRef Filename = Stat->first(); Generator.insert(Filename.data(), Stat->second); } // Create the on-disk hash table in a buffer. SmallString<4096> StatCacheData; uint32_t BucketOffset; { llvm::raw_svector_ostream Out(StatCacheData); // Make sure that no bucket is at offset 0 clang::io::Emit32(Out, 0); BucketOffset = Generator.Emit(Out); } // Create a blob abbreviation using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(STAT_CACHE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev); // Write the stat cache RecordData Record; Record.push_back(STAT_CACHE); Record.push_back(BucketOffset); Record.push_back(NumStatEntries); Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str()); } //===----------------------------------------------------------------------===// // Source Manager Serialization //===----------------------------------------------------------------------===// /// \brief Create an abbreviation for the SLocEntry that refers to a /// file. static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives // FileEntry fields. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // BufferOverridden Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name return Stream.EmitAbbrev(Abbrev); } /// \brief Create an abbreviation for the SLocEntry that refers to a /// buffer. static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob return Stream.EmitAbbrev(Abbrev); } /// \brief Create an abbreviation for the SLocEntry that refers to a /// buffer's blob. static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_BLOB)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob return Stream.EmitAbbrev(Abbrev); } /// \brief Create an abbreviation for the SLocEntry that refers to a macro /// expansion. static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_EXPANSION_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Start location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // End location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length return Stream.EmitAbbrev(Abbrev); } namespace { // Trait used for the on-disk hash table of header search information. class HeaderFileInfoTrait { ASTWriter &Writer; const HeaderSearch &HS; // Keep track of the framework names we've used during serialization. SmallVector FrameworkStringData; llvm::StringMap FrameworkNameOffset; public: HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS) : Writer(Writer), HS(HS) { } typedef const char *key_type; typedef key_type key_type_ref; typedef HeaderFileInfo data_type; typedef const data_type &data_type_ref; static unsigned ComputeHash(const char *path) { // The hash is based only on the filename portion of the key, so that the // reader can match based on filenames when symlinking or excess path // elements ("foo/../", "../") change the form of the name. However, // complete path is still the key. return llvm::HashString(llvm::sys::path::filename(path)); } std::pair EmitKeyDataLength(raw_ostream& Out, const char *path, data_type_ref Data) { unsigned StrLen = strlen(path); clang::io::Emit16(Out, StrLen); unsigned DataLen = 1 + 2 + 4 + 4; clang::io::Emit8(Out, DataLen); return std::make_pair(StrLen + 1, DataLen); } void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) { Out.write(path, KeyLen); } void EmitData(raw_ostream &Out, key_type_ref, data_type_ref Data, unsigned DataLen) { using namespace clang::io; uint64_t Start = Out.tell(); (void)Start; unsigned char Flags = (Data.isImport << 5) | (Data.isPragmaOnce << 4) | (Data.DirInfo << 2) | (Data.Resolved << 1) | Data.IndexHeaderMapHeader; Emit8(Out, (uint8_t)Flags); Emit16(Out, (uint16_t) Data.NumIncludes); if (!Data.ControllingMacro) Emit32(Out, (uint32_t)Data.ControllingMacroID); else Emit32(Out, (uint32_t)Writer.getIdentifierRef(Data.ControllingMacro)); unsigned Offset = 0; if (!Data.Framework.empty()) { // If this header refers into a framework, save the framework name. llvm::StringMap::iterator Pos = FrameworkNameOffset.find(Data.Framework); if (Pos == FrameworkNameOffset.end()) { Offset = FrameworkStringData.size() + 1; FrameworkStringData.append(Data.Framework.begin(), Data.Framework.end()); FrameworkStringData.push_back(0); FrameworkNameOffset[Data.Framework] = Offset; } else Offset = Pos->second; } Emit32(Out, Offset); assert(Out.tell() - Start == DataLen && "Wrong data length"); } const char *strings_begin() const { return FrameworkStringData.begin(); } const char *strings_end() const { return FrameworkStringData.end(); } }; } // end anonymous namespace /// \brief Write the header search block for the list of files that /// /// \param HS The header search structure to save. /// /// \param Chain Whether we're creating a chained AST file. void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) { SmallVector FilesByUID; HS.getFileMgr().GetUniqueIDMapping(FilesByUID); if (FilesByUID.size() > HS.header_file_size()) FilesByUID.resize(HS.header_file_size()); HeaderFileInfoTrait GeneratorTrait(*this, HS); OnDiskChainedHashTableGenerator Generator; SmallVector SavedStrings; unsigned NumHeaderSearchEntries = 0; for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) { const FileEntry *File = FilesByUID[UID]; if (!File) continue; // Use HeaderSearch's getFileInfo to make sure we get the HeaderFileInfo // from the external source if it was not provided already. const HeaderFileInfo &HFI = HS.getFileInfo(File); if (HFI.External && Chain) continue; // Turn the file name into an absolute path, if it isn't already. const char *Filename = File->getName(); Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); // If we performed any translation on the file name at all, we need to // save this string, since the generator will refer to it later. if (Filename != File->getName()) { Filename = strdup(Filename); SavedStrings.push_back(Filename); } Generator.insert(Filename, HFI, GeneratorTrait); ++NumHeaderSearchEntries; } // Create the on-disk hash table in a buffer. SmallString<4096> TableData; uint32_t BucketOffset; { llvm::raw_svector_ostream Out(TableData); // Make sure that no bucket is at offset 0 clang::io::Emit32(Out, 0); BucketOffset = Generator.Emit(Out, GeneratorTrait); } // Create a blob abbreviation using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned TableAbbrev = Stream.EmitAbbrev(Abbrev); // Write the header search table RecordData Record; Record.push_back(HEADER_SEARCH_TABLE); Record.push_back(BucketOffset); Record.push_back(NumHeaderSearchEntries); Record.push_back(TableData.size()); TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end()); Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData.str()); // Free all of the strings we had to duplicate. for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I) free((void*)SavedStrings[I]); } /// \brief Writes the block containing the serialized form of the /// source manager. /// /// TODO: We should probably use an on-disk hash table (stored in a /// blob), indexed based on the file name, so that we only create /// entries for files that we actually need. In the common case (no /// errors), we probably won't have to create file entries for any of /// the files in the AST. void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, const Preprocessor &PP, StringRef isysroot) { RecordData Record; // Enter the source manager block. Stream.EnterSubblock(SOURCE_MANAGER_BLOCK_ID, 3); // Abbreviations for the various kinds of source-location entries. unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream); unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream); unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream); unsigned SLocExpansionAbbrv = CreateSLocExpansionAbbrev(Stream); // Write out the source location entry table. We skip the first // entry, which is always the same dummy entry. std::vector SLocEntryOffsets; // Write out the offsets of only source location file entries. // We will go through them in ASTReader::validateFileEntries(). std::vector SLocFileEntryOffsets; RecordData PreloadSLocs; SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1); for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { // Get this source location entry. const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I); // Record the offset of this source-location entry. SLocEntryOffsets.push_back(Stream.GetCurrentBitNo()); // Figure out which record code to use. unsigned Code; if (SLoc->isFile()) { const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache(); if (Cache->OrigEntry) { Code = SM_SLOC_FILE_ENTRY; SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo()); } else Code = SM_SLOC_BUFFER_ENTRY; } else Code = SM_SLOC_EXPANSION_ENTRY; Record.clear(); Record.push_back(Code); // Starting offset of this entry within this module, so skip the dummy. Record.push_back(SLoc->getOffset() - 2); if (SLoc->isFile()) { const SrcMgr::FileInfo &File = SLoc->getFile(); Record.push_back(File.getIncludeLoc().getRawEncoding()); Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding Record.push_back(File.hasLineDirectives()); const SrcMgr::ContentCache *Content = File.getContentCache(); if (Content->OrigEntry) { assert(Content->OrigEntry == Content->ContentsEntry && "Writing to AST an overridden file is not supported"); // The source location entry is a file. The blob associated // with this entry is the file name. // Emit size/modification time for this file. Record.push_back(Content->OrigEntry->getSize()); Record.push_back(Content->OrigEntry->getModificationTime()); Record.push_back(Content->BufferOverridden); Record.push_back(File.NumCreatedFIDs); FileDeclIDsTy::iterator FDI = FileDeclIDs.find(SLoc); if (FDI != FileDeclIDs.end()) { Record.push_back(FDI->second->FirstDeclIndex); Record.push_back(FDI->second->DeclIDs.size()); } else { Record.push_back(0); Record.push_back(0); } // Turn the file name into an absolute path, if it isn't already. const char *Filename = Content->OrigEntry->getName(); SmallString<128> FilePath(Filename); // Ask the file manager to fixup the relative path for us. This will // honor the working directory. SourceMgr.getFileManager().FixupRelativePath(FilePath); // FIXME: This call to make_absolute shouldn't be necessary, the // call to FixupRelativePath should always return an absolute path. llvm::sys::fs::make_absolute(FilePath); Filename = FilePath.c_str(); Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename); if (Content->BufferOverridden) { Record.clear(); Record.push_back(SM_SLOC_BUFFER_BLOB); const llvm::MemoryBuffer *Buffer = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager()); Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, StringRef(Buffer->getBufferStart(), Buffer->getBufferSize() + 1)); } } else { // The source location entry is a buffer. The blob associated // with this entry contains the contents of the buffer. // We add one to the size so that we capture the trailing NULL // that is required by llvm::MemoryBuffer::getMemBuffer (on // the reader side). const llvm::MemoryBuffer *Buffer = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager()); const char *Name = Buffer->getBufferIdentifier(); Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, StringRef(Name, strlen(Name) + 1)); Record.clear(); Record.push_back(SM_SLOC_BUFFER_BLOB); Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, StringRef(Buffer->getBufferStart(), Buffer->getBufferSize() + 1)); if (strcmp(Name, "") == 0) { PreloadSLocs.push_back(SLocEntryOffsets.size()); } } } else { // The source location entry is a macro expansion. const SrcMgr::ExpansionInfo &Expansion = SLoc->getExpansion(); Record.push_back(Expansion.getSpellingLoc().getRawEncoding()); Record.push_back(Expansion.getExpansionLocStart().getRawEncoding()); Record.push_back(Expansion.isMacroArgExpansion() ? 0 : Expansion.getExpansionLocEnd().getRawEncoding()); // Compute the token length for this macro expansion. unsigned NextOffset = SourceMgr.getNextLocalOffset(); if (I + 1 != N) NextOffset = SourceMgr.getLocalSLocEntry(I + 1).getOffset(); Record.push_back(NextOffset - SLoc->getOffset() - 1); Stream.EmitRecordWithAbbrev(SLocExpansionAbbrv, Record); } } Stream.ExitBlock(); if (SLocEntryOffsets.empty()) return; // Write the source-location offsets table into the AST block. This // table is used for lazily loading source-location information. using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev); Record.clear(); Record.push_back(SOURCE_LOCATION_OFFSETS); Record.push_back(SLocEntryOffsets.size()); Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets)); Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(FILE_SOURCE_LOCATION_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets unsigned SLocFileOffsetsAbbrev = Stream.EmitAbbrev(Abbrev); Record.clear(); Record.push_back(FILE_SOURCE_LOCATION_OFFSETS); Record.push_back(SLocFileEntryOffsets.size()); Stream.EmitRecordWithBlob(SLocFileOffsetsAbbrev, Record, data(SLocFileEntryOffsets)); // Write the source location entry preloads array, telling the AST // reader which source locations entries it should load eagerly. Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs); // Write the line table. It depends on remapping working, so it must come // after the source location offsets. if (SourceMgr.hasLineTable()) { LineTableInfo &LineTable = SourceMgr.getLineTable(); Record.clear(); // Emit the file names Record.push_back(LineTable.getNumFilenames()); for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) { // Emit the file name const char *Filename = LineTable.getFilename(I); Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); unsigned FilenameLen = Filename? strlen(Filename) : 0; Record.push_back(FilenameLen); if (FilenameLen) Record.insert(Record.end(), Filename, Filename + FilenameLen); } // Emit the line entries for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end(); L != LEnd; ++L) { // Only emit entries for local files. if (L->first < 0) continue; // Emit the file ID Record.push_back(L->first); // Emit the line entries Record.push_back(L->second.size()); for (std::vector::iterator LE = L->second.begin(), LEEnd = L->second.end(); LE != LEEnd; ++LE) { Record.push_back(LE->FileOffset); Record.push_back(LE->LineNo); Record.push_back(LE->FilenameID); Record.push_back((unsigned)LE->FileKind); Record.push_back(LE->IncludeOffset); } } Stream.EmitRecord(SOURCE_MANAGER_LINE_TABLE, Record); } } //===----------------------------------------------------------------------===// // Preprocessor Serialization //===----------------------------------------------------------------------===// static int compareMacroDefinitions(const void *XPtr, const void *YPtr) { const std::pair &X = *(const std::pair*)XPtr; const std::pair &Y = *(const std::pair*)YPtr; return X.first->getName().compare(Y.first->getName()); } /// \brief Writes the block containing the serialized form of the /// preprocessor. /// void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); if (PPRec) WritePreprocessorDetail(*PPRec); RecordData Record; // If the preprocessor __COUNTER__ value has been bumped, remember it. if (PP.getCounterValue() != 0) { Record.push_back(PP.getCounterValue()); Stream.EmitRecord(PP_COUNTER_VALUE, Record); Record.clear(); } // Enter the preprocessor block. Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3); // If the AST file contains __DATE__ or __TIME__ emit a warning about this. // FIXME: use diagnostics subsystem for localization etc. if (PP.SawDateOrTime()) fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n"); // Loop over all the macro definitions that are live at the end of the file, // emitting each to the PP section. // Construct the list of macro definitions that need to be serialized. SmallVector, 2> MacrosToEmit; llvm::SmallPtrSet MacroDefinitionsSeen; for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0), E = PP.macro_end(Chain == 0); I != E; ++I) { const IdentifierInfo *Name = I->first; if (!IsModule || I->second->isPublic()) { MacroDefinitionsSeen.insert(Name); MacrosToEmit.push_back(std::make_pair(I->first, I->second)); } } // Sort the set of macro definitions that need to be serialized by the // name of the macro, to provide a stable ordering. llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(), &compareMacroDefinitions); // Resolve any identifiers that defined macros at the time they were // deserialized, adding them to the list of macros to emit (if appropriate). for (unsigned I = 0, N = DeserializedMacroNames.size(); I != N; ++I) { IdentifierInfo *Name = const_cast(DeserializedMacroNames[I]); if (Name->hasMacroDefinition() && MacroDefinitionsSeen.insert(Name)) MacrosToEmit.push_back(std::make_pair(Name, PP.getMacroInfo(Name))); } for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) { const IdentifierInfo *Name = MacrosToEmit[I].first; MacroInfo *MI = MacrosToEmit[I].second; if (!MI) continue; // Don't emit builtin macros like __LINE__ to the AST file unless they have // been redefined by the header (in which case they are not isBuiltinMacro). // Also skip macros from a AST file if we're chaining. // FIXME: There is a (probably minor) optimization we could do here, if // the macro comes from the original PCH but the identifier comes from a // chained PCH, by storing the offset into the original PCH rather than // writing the macro definition a second time. if (MI->isBuiltinMacro() || (Chain && Name->isFromAST() && !Name->hasChangedSinceDeserialization() && MI->isFromAST() && !MI->hasChangedAfterLoad())) continue; AddIdentifierRef(Name, Record); MacroOffsets[Name] = Stream.GetCurrentBitNo(); Record.push_back(MI->getDefinitionLoc().getRawEncoding()); Record.push_back(MI->isUsed()); Record.push_back(MI->isPublic()); AddSourceLocation(MI->getVisibilityLocation(), Record); unsigned Code; if (MI->isObjectLike()) { Code = PP_MACRO_OBJECT_LIKE; } else { Code = PP_MACRO_FUNCTION_LIKE; Record.push_back(MI->isC99Varargs()); Record.push_back(MI->isGNUVarargs()); Record.push_back(MI->getNumArgs()); for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); I != E; ++I) AddIdentifierRef(*I, Record); } // If we have a detailed preprocessing record, record the macro definition // ID that corresponds to this macro. if (PPRec) Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]); Stream.EmitRecord(Code, Record); Record.clear(); // Emit the tokens array. for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { // Note that we know that the preprocessor does not have any annotation // tokens in it because they are created by the parser, and thus can't be // in a macro definition. const Token &Tok = MI->getReplacementToken(TokNo); Record.push_back(Tok.getLocation().getRawEncoding()); Record.push_back(Tok.getLength()); // FIXME: When reading literal tokens, reconstruct the literal pointer if // it is needed. AddIdentifierRef(Tok.getIdentifierInfo(), Record); // FIXME: Should translate token kind to a stable encoding. Record.push_back(Tok.getKind()); // FIXME: Should translate token flags to a stable encoding. Record.push_back(Tok.getFlags()); Stream.EmitRecord(PP_TOKEN, Record); Record.clear(); } ++NumMacros; } Stream.ExitBlock(); } void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { if (PPRec.local_begin() == PPRec.local_end()) return; SmallVector PreprocessedEntityOffsets; // Enter the preprocessor block. Stream.EnterSubblock(PREPROCESSOR_DETAIL_BLOCK_ID, 3); // If the preprocessor has a preprocessing record, emit it. unsigned NumPreprocessingRecords = 0; using namespace llvm; // Set up the abbreviation for unsigned InclusionAbbrev = 0; { BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); InclusionAbbrev = Stream.EmitAbbrev(Abbrev); } unsigned FirstPreprocessorEntityID = (Chain ? PPRec.getNumLoadedPreprocessedEntities() : 0) + NUM_PREDEF_PP_ENTITY_IDS; unsigned NextPreprocessorEntityID = FirstPreprocessorEntityID; RecordData Record; for (PreprocessingRecord::iterator E = PPRec.local_begin(), EEnd = PPRec.local_end(); E != EEnd; (void)++E, ++NumPreprocessingRecords, ++NextPreprocessorEntityID) { Record.clear(); PreprocessedEntityOffsets.push_back(PPEntityOffset((*E)->getSourceRange(), Stream.GetCurrentBitNo())); if (MacroDefinition *MD = dyn_cast(*E)) { // Record this macro definition's ID. MacroDefinitions[MD] = NextPreprocessorEntityID; AddIdentifierRef(MD->getName(), Record); Stream.EmitRecord(PPD_MACRO_DEFINITION, Record); continue; } if (MacroExpansion *ME = dyn_cast(*E)) { Record.push_back(ME->isBuiltinMacro()); if (ME->isBuiltinMacro()) AddIdentifierRef(ME->getName(), Record); else Record.push_back(MacroDefinitions[ME->getDefinition()]); Stream.EmitRecord(PPD_MACRO_EXPANSION, Record); continue; } if (InclusionDirective *ID = dyn_cast(*E)) { Record.push_back(PPD_INCLUSION_DIRECTIVE); Record.push_back(ID->getFileName().size()); Record.push_back(ID->wasInQuotes()); Record.push_back(static_cast(ID->getKind())); SmallString<64> Buffer; Buffer += ID->getFileName(); // Check that the FileEntry is not null because it was not resolved and // we create a PCH even with compiler errors. if (ID->getFile()) Buffer += ID->getFile()->getName(); Stream.EmitRecordWithBlob(InclusionAbbrev, Record, Buffer); continue; } llvm_unreachable("Unhandled PreprocessedEntity in ASTWriter"); } Stream.ExitBlock(); // Write the offsets table for the preprocessing record. if (NumPreprocessingRecords > 0) { assert(PreprocessedEntityOffsets.size() == NumPreprocessingRecords); // Write the offsets table for identifier IDs. using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned PPEOffsetAbbrev = Stream.EmitAbbrev(Abbrev); Record.clear(); Record.push_back(PPD_ENTITIES_OFFSETS); Record.push_back(FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS); Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record, data(PreprocessedEntityOffsets)); } } unsigned ASTWriter::getSubmoduleID(Module *Mod) { llvm::DenseMap::iterator Known = SubmoduleIDs.find(Mod); if (Known != SubmoduleIDs.end()) return Known->second; return SubmoduleIDs[Mod] = NextSubmoduleID++; } /// \brief Compute the number of modules within the given tree (including the /// given module). static unsigned getNumberOfModules(Module *Mod) { unsigned ChildModules = 0; for (Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); Sub != SubEnd; ++Sub) ChildModules += getNumberOfModules(*Sub); return ChildModules + 1; } void ASTWriter::WriteSubmodules(Module *WritingModule) { // Determine the dependencies of our module and each of it's submodules. // FIXME: This feels like it belongs somewhere else, but there are no // other consumers of this information. SourceManager &SrcMgr = PP->getSourceManager(); ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap(); for (ASTContext::import_iterator I = Context->local_import_begin(), IEnd = Context->local_import_end(); I != IEnd; ++I) { if (Module *ImportedFrom = ModMap.inferModuleFromLocation(FullSourceLoc(I->getLocation(), SrcMgr))) { ImportedFrom->Imports.push_back(I->getImportedModule()); } } // Enter the submodule description block. Stream.EnterSubblock(SUBMODULE_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); // Write the abbreviations needed for the submodules block. using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev); Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned UmbrellaAbbrev = Stream.EmitAbbrev(Abbrev); Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev); Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev); Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev); // Write the submodule metadata block. RecordData Record; Record.push_back(getNumberOfModules(WritingModule)); Record.push_back(FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS); Stream.EmitRecord(SUBMODULE_METADATA, Record); // Write all of the submodules. std::queue Q; Q.push(WritingModule); while (!Q.empty()) { Module *Mod = Q.front(); Q.pop(); unsigned ID = getSubmoduleID(Mod); // Emit the definition of the block. Record.clear(); Record.push_back(SUBMODULE_DEFINITION); Record.push_back(ID); if (Mod->Parent) { assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?"); Record.push_back(SubmoduleIDs[Mod->Parent]); } else { Record.push_back(0); } Record.push_back(Mod->IsFramework); Record.push_back(Mod->IsExplicit); Record.push_back(Mod->IsSystem); Record.push_back(Mod->InferSubmodules); Record.push_back(Mod->InferExplicitSubmodules); Record.push_back(Mod->InferExportWildcard); Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); // Emit the requirements. for (unsigned I = 0, N = Mod->Requires.size(); I != N; ++I) { Record.clear(); Record.push_back(SUBMODULE_REQUIRES); Stream.EmitRecordWithBlob(RequiresAbbrev, Record, Mod->Requires[I].data(), Mod->Requires[I].size()); } // Emit the umbrella header, if there is one. if (const FileEntry *UmbrellaHeader = Mod->getUmbrellaHeader()) { Record.clear(); Record.push_back(SUBMODULE_UMBRELLA_HEADER); Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record, UmbrellaHeader->getName()); } else if (const DirectoryEntry *UmbrellaDir = Mod->getUmbrellaDir()) { Record.clear(); Record.push_back(SUBMODULE_UMBRELLA_DIR); Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record, UmbrellaDir->getName()); } // Emit the headers. for (unsigned I = 0, N = Mod->Headers.size(); I != N; ++I) { Record.clear(); Record.push_back(SUBMODULE_HEADER); Stream.EmitRecordWithBlob(HeaderAbbrev, Record, Mod->Headers[I]->getName()); } // Emit the imports. if (!Mod->Imports.empty()) { Record.clear(); for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) { unsigned ImportedID = getSubmoduleID(Mod->Imports[I]); assert(ImportedID && "Unknown submodule!"); Record.push_back(ImportedID); } Stream.EmitRecord(SUBMODULE_IMPORTS, Record); } // Emit the exports. if (!Mod->Exports.empty()) { Record.clear(); for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) { if (Module *Exported = Mod->Exports[I].getPointer()) { unsigned ExportedID = SubmoduleIDs[Exported]; assert(ExportedID > 0 && "Unknown submodule ID?"); Record.push_back(ExportedID); } else { Record.push_back(0); } Record.push_back(Mod->Exports[I].getInt()); } Stream.EmitRecord(SUBMODULE_EXPORTS, Record); } // Queue up the submodules of this module. for (Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); Sub != SubEnd; ++Sub) Q.push(*Sub); } Stream.ExitBlock(); assert((NextSubmoduleID - FirstSubmoduleID == getNumberOfModules(WritingModule)) && "Wrong # of submodules"); } serialization::SubmoduleID ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) { if (Loc.isInvalid() || !WritingModule) return 0; // No submodule // Find the module that owns this location. ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap(); Module *OwningMod = ModMap.inferModuleFromLocation(FullSourceLoc(Loc,PP->getSourceManager())); if (!OwningMod) return 0; // Check whether this submodule is part of our own module. if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(WritingModule)) return 0; return getSubmoduleID(OwningMod); } void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) { RecordData Record; for (DiagnosticsEngine::DiagStatePointsTy::const_iterator I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end(); I != E; ++I) { const DiagnosticsEngine::DiagStatePoint &point = *I; if (point.Loc.isInvalid()) continue; Record.push_back(point.Loc.getRawEncoding()); for (DiagnosticsEngine::DiagState::const_iterator I = point.State->begin(), E = point.State->end(); I != E; ++I) { if (I->second.isPragma()) { Record.push_back(I->first); Record.push_back(I->second.getMapping()); } } Record.push_back(-1); // mark the end of the diag/map pairs for this // location. } if (!Record.empty()) Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record); } void ASTWriter::WriteCXXBaseSpecifiersOffsets() { if (CXXBaseSpecifiersOffsets.empty()) return; RecordData Record; // Create a blob abbreviation for the C++ base specifiers offsets. using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); // Write the base specifier offsets table. Record.clear(); Record.push_back(CXX_BASE_SPECIFIER_OFFSETS); Record.push_back(CXXBaseSpecifiersOffsets.size()); Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record, data(CXXBaseSpecifiersOffsets)); } //===----------------------------------------------------------------------===// // Type Serialization //===----------------------------------------------------------------------===// /// \brief Write the representation of a type to the AST stream. void ASTWriter::WriteType(QualType T) { TypeIdx &Idx = TypeIdxs[T]; if (Idx.getIndex() == 0) // we haven't seen this type before. Idx = TypeIdx(NextTypeID++); assert(Idx.getIndex() >= FirstTypeID && "Re-writing a type from a prior AST"); // Record the offset for this type. unsigned Index = Idx.getIndex() - FirstTypeID; if (TypeOffsets.size() == Index) TypeOffsets.push_back(Stream.GetCurrentBitNo()); else if (TypeOffsets.size() < Index) { TypeOffsets.resize(Index + 1); TypeOffsets[Index] = Stream.GetCurrentBitNo(); } RecordData Record; // Emit the type's representation. ASTTypeWriter W(*this, Record); if (T.hasLocalNonFastQualifiers()) { Qualifiers Qs = T.getLocalQualifiers(); AddTypeRef(T.getLocalUnqualifiedType(), Record); Record.push_back(Qs.getAsOpaqueValue()); W.Code = TYPE_EXT_QUAL; } else { switch (T->getTypeClass()) { // For all of the concrete, non-dependent types, call the // appropriate visitor function. #define TYPE(Class, Base) \ case Type::Class: W.Visit##Class##Type(cast(T)); break; #define ABSTRACT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" } } // Emit the serialized record. Stream.EmitRecord(W.Code, Record); // Flush any expressions that were written as part of this type. FlushStmts(); } //===----------------------------------------------------------------------===// // Declaration Serialization //===----------------------------------------------------------------------===// /// \brief Write the block containing all of the declaration IDs /// lexically declared within the given DeclContext. /// /// \returns the offset of the DECL_CONTEXT_LEXICAL block within the /// bistream, or 0 if no block was written. uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC) { if (DC->decls_empty()) return 0; uint64_t Offset = Stream.GetCurrentBitNo(); RecordData Record; Record.push_back(DECL_CONTEXT_LEXICAL); SmallVector Decls; for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); D != DEnd; ++D) Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D))); ++NumLexicalDeclContexts; Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, data(Decls)); return Offset; } void ASTWriter::WriteTypeDeclOffsets() { using namespace llvm; RecordData Record; // Write the type offsets array BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev); Record.clear(); Record.push_back(TYPE_OFFSET); Record.push_back(TypeOffsets.size()); Record.push_back(FirstTypeID - NUM_PREDEF_TYPE_IDS); Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, data(TypeOffsets)); // Write the declaration offsets array Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(DECL_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base decl ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev); Record.clear(); Record.push_back(DECL_OFFSET); Record.push_back(DeclOffsets.size()); Record.push_back(FirstDeclID - NUM_PREDEF_DECL_IDS); Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, data(DeclOffsets)); } void ASTWriter::WriteFileDeclIDsMap() { using namespace llvm; RecordData Record; // Join the vectors of DeclIDs from all files. SmallVector FileSortedIDs; for (FileDeclIDsTy::iterator FI = FileDeclIDs.begin(), FE = FileDeclIDs.end(); FI != FE; ++FI) { DeclIDInFileInfo &Info = *FI->second; Info.FirstDeclIndex = FileSortedIDs.size(); for (LocDeclIDsTy::iterator DI = Info.DeclIDs.begin(), DE = Info.DeclIDs.end(); DI != DE; ++DI) FileSortedIDs.push_back(DI->second); } BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); Record.push_back(FILE_SORTED_DECLS); Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileSortedIDs)); } //===----------------------------------------------------------------------===// // Global Method Pool and Selector Serialization //===----------------------------------------------------------------------===// namespace { // Trait used for the on-disk hash table used in the method pool. class ASTMethodPoolTrait { ASTWriter &Writer; public: typedef Selector key_type; typedef key_type key_type_ref; struct data_type { SelectorID ID; ObjCMethodList Instance, Factory; }; typedef const data_type& data_type_ref; explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) { } static unsigned ComputeHash(Selector Sel) { return serialization::ComputeHash(Sel); } std::pair EmitKeyDataLength(raw_ostream& Out, Selector Sel, data_type_ref Methods) { unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4); clang::io::Emit16(Out, KeyLen); unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->Next) if (Method->Method) DataLen += 4; for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->Next) if (Method->Method) DataLen += 4; clang::io::Emit16(Out, DataLen); return std::make_pair(KeyLen, DataLen); } void EmitKey(raw_ostream& Out, Selector Sel, unsigned) { uint64_t Start = Out.tell(); assert((Start >> 32) == 0 && "Selector key offset too large"); Writer.SetSelectorOffset(Sel, Start); unsigned N = Sel.getNumArgs(); clang::io::Emit16(Out, N); if (N == 0) N = 1; for (unsigned I = 0; I != N; ++I) clang::io::Emit32(Out, Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); } void EmitData(raw_ostream& Out, key_type_ref, data_type_ref Methods, unsigned DataLen) { uint64_t Start = Out.tell(); (void)Start; clang::io::Emit32(Out, Methods.ID); unsigned NumInstanceMethods = 0; for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->Next) if (Method->Method) ++NumInstanceMethods; unsigned NumFactoryMethods = 0; for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->Next) if (Method->Method) ++NumFactoryMethods; clang::io::Emit16(Out, NumInstanceMethods); clang::io::Emit16(Out, NumFactoryMethods); for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->Next) if (Method->Method) clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->Next) if (Method->Method) clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } }; } // end anonymous namespace /// \brief Write ObjC data: selectors and the method pool. /// /// The method pool contains both instance and factory methods, stored /// in an on-disk hash table indexed by the selector. The hash table also /// contains an empty entry for every other selector known to Sema. void ASTWriter::WriteSelectors(Sema &SemaRef) { using namespace llvm; // Do we have to do anything at all? if (SemaRef.MethodPool.empty() && SelectorIDs.empty()) return; unsigned NumTableEntries = 0; // Create and write out the blob that contains selectors and the method pool. { OnDiskChainedHashTableGenerator Generator; ASTMethodPoolTrait Trait(*this); // Create the on-disk hash table representation. We walk through every // selector we've seen and look it up in the method pool. SelectorOffsets.resize(NextSelectorID - FirstSelectorID); for (llvm::DenseMap::iterator I = SelectorIDs.begin(), E = SelectorIDs.end(); I != E; ++I) { Selector S = I->first; Sema::GlobalMethodPool::iterator F = SemaRef.MethodPool.find(S); ASTMethodPoolTrait::data_type Data = { I->second, ObjCMethodList(), ObjCMethodList() }; if (F != SemaRef.MethodPool.end()) { Data.Instance = F->second.first; Data.Factory = F->second.second; } // Only write this selector if it's not in an existing AST or something // changed. if (Chain && I->second < FirstSelectorID) { // Selector already exists. Did it change? bool changed = false; for (ObjCMethodList *M = &Data.Instance; !changed && M && M->Method; M = M->Next) { if (!M->Method->isFromASTFile()) changed = true; } for (ObjCMethodList *M = &Data.Factory; !changed && M && M->Method; M = M->Next) { if (!M->Method->isFromASTFile()) changed = true; } if (!changed) continue; } else if (Data.Instance.Method || Data.Factory.Method) { // A new method pool entry. ++NumTableEntries; } Generator.insert(S, Data, Trait); } // Create the on-disk hash table in a buffer. SmallString<4096> MethodPool; uint32_t BucketOffset; { ASTMethodPoolTrait Trait(*this); llvm::raw_svector_ostream Out(MethodPool); // Make sure that no bucket is at offset 0 clang::io::Emit32(Out, 0); BucketOffset = Generator.Emit(Out, Trait); } // Create a blob abbreviation BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(METHOD_POOL)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev); // Write the method pool RecordData Record; Record.push_back(METHOD_POOL); Record.push_back(BucketOffset); Record.push_back(NumTableEntries); Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool.str()); // Create a blob abbreviation for the selector table offsets. Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SELECTOR_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev); // Write the selector offsets table. Record.clear(); Record.push_back(SELECTOR_OFFSETS); Record.push_back(SelectorOffsets.size()); Record.push_back(FirstSelectorID - NUM_PREDEF_SELECTOR_IDS); Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, data(SelectorOffsets)); } } /// \brief Write the selectors referenced in @selector expression into AST file. void ASTWriter::WriteReferencedSelectorsPool(Sema &SemaRef) { using namespace llvm; if (SemaRef.ReferencedSelectors.empty()) return; RecordData Record; // Note: this writes out all references even for a dependent AST. But it is // very tricky to fix, and given that @selector shouldn't really appear in // headers, probably not worth it. It's not a correctness issue. for (DenseMap::iterator S = SemaRef.ReferencedSelectors.begin(), E = SemaRef.ReferencedSelectors.end(); S != E; ++S) { Selector Sel = (*S).first; SourceLocation Loc = (*S).second; AddSelectorRef(Sel, Record); AddSourceLocation(Loc, Record); } Stream.EmitRecord(REFERENCED_SELECTOR_POOL, Record); } //===----------------------------------------------------------------------===// // Identifier Table Serialization //===----------------------------------------------------------------------===// namespace { class ASTIdentifierTableTrait { ASTWriter &Writer; Preprocessor &PP; IdentifierResolver &IdResolver; bool IsModule; /// \brief Determines whether this is an "interesting" identifier /// that needs a full IdentifierInfo structure written into the hash /// table. bool isInterestingIdentifier(IdentifierInfo *II, MacroInfo *&Macro) { if (II->isPoisoned() || II->isExtensionToken() || II->getObjCOrBuiltinID() || II->hasRevertedTokenIDToIdentifier() || II->getFETokenInfo()) return true; return hasMacroDefinition(II, Macro); } bool hasMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) { if (!II->hasMacroDefinition()) return false; if (Macro || (Macro = PP.getMacroInfo(II))) return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic()); return false; } public: typedef IdentifierInfo* key_type; typedef key_type key_type_ref; typedef IdentID data_type; typedef data_type data_type_ref; ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule) : Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule) { } static unsigned ComputeHash(const IdentifierInfo* II) { return llvm::HashString(II->getName()); } std::pair EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) { unsigned KeyLen = II->getLength() + 1; unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 MacroInfo *Macro = 0; if (isInterestingIdentifier(II, Macro)) { DataLen += 2; // 2 bytes for builtin ID, flags if (hasMacroDefinition(II, Macro)) DataLen += 8; for (IdentifierResolver::iterator D = IdResolver.begin(II), DEnd = IdResolver.end(); D != DEnd; ++D) DataLen += sizeof(DeclID); } clang::io::Emit16(Out, DataLen); // We emit the key length after the data length so that every // string is preceded by a 16-bit length. This matches the PTH // format for storing identifiers. clang::io::Emit16(Out, KeyLen); return std::make_pair(KeyLen, DataLen); } void EmitKey(raw_ostream& Out, const IdentifierInfo* II, unsigned KeyLen) { // Record the location of the key data. This is used when generating // the mapping from persistent IDs to strings. Writer.SetIdentifierOffset(II, Out.tell()); Out.write(II->getNameStart(), KeyLen); } void EmitData(raw_ostream& Out, IdentifierInfo* II, IdentID ID, unsigned) { MacroInfo *Macro = 0; if (!isInterestingIdentifier(II, Macro)) { clang::io::Emit32(Out, ID << 1); return; } clang::io::Emit32(Out, (ID << 1) | 0x01); uint32_t Bits = 0; bool HasMacroDefinition = hasMacroDefinition(II, Macro); Bits = (uint32_t)II->getObjCOrBuiltinID(); assert((Bits & 0x7ff) == Bits && "ObjCOrBuiltinID too big for ASTReader."); Bits = (Bits << 1) | unsigned(HasMacroDefinition); Bits = (Bits << 1) | unsigned(II->isExtensionToken()); Bits = (Bits << 1) | unsigned(II->isPoisoned()); Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); clang::io::Emit16(Out, Bits); if (HasMacroDefinition) { clang::io::Emit32(Out, Writer.getMacroOffset(II)); clang::io::Emit32(Out, Writer.inferSubmoduleIDFromLocation(Macro->getDefinitionLoc())); } // Emit the declaration IDs in reverse order, because the // IdentifierResolver provides the declarations as they would be // visible (e.g., the function "stat" would come before the struct // "stat"), but the ASTReader adds declarations to the end of the list // (so we need to see the struct "status" before the function "status"). // Only emit declarations that aren't from a chained PCH, though. SmallVector Decls(IdResolver.begin(II), IdResolver.end()); for (SmallVector::reverse_iterator D = Decls.rbegin(), DEnd = Decls.rend(); D != DEnd; ++D) clang::io::Emit32(Out, Writer.getDeclID(*D)); } }; } // end anonymous namespace /// \brief Write the identifier table into the AST file. /// /// The identifier table consists of a blob containing string data /// (the actual identifiers themselves) and a separate "offsets" index /// that maps identifier IDs to locations within the blob. void ASTWriter::WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule) { using namespace llvm; // Create and write out the blob that contains the identifier // strings. { OnDiskChainedHashTableGenerator Generator; ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule); // Look for any identifiers that were named while processing the // headers, but are otherwise not needed. We add these to the hash // table to enable checking of the predefines buffer in the case // where the user adds new macro definitions when building the AST // file. for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), IDEnd = PP.getIdentifierTable().end(); ID != IDEnd; ++ID) getIdentifierRef(ID->second); // Create the on-disk hash table representation. We only store offsets // for identifiers that appear here for the first time. IdentifierOffsets.resize(NextIdentID - FirstIdentID); for (llvm::DenseMap::iterator ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end(); ID != IDEnd; ++ID) { assert(ID->first && "NULL identifier in identifier table"); if (!Chain || !ID->first->isFromAST() || ID->first->hasChangedSinceDeserialization()) Generator.insert(const_cast(ID->first), ID->second, Trait); } // Create the on-disk hash table in a buffer. SmallString<4096> IdentifierTable; uint32_t BucketOffset; { ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule); llvm::raw_svector_ostream Out(IdentifierTable); // Make sure that no bucket is at offset 0 clang::io::Emit32(Out, 0); BucketOffset = Generator.Emit(Out, Trait); } // Create a blob abbreviation BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_TABLE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev); // Write the identifier table RecordData Record; Record.push_back(IDENTIFIER_TABLE); Record.push_back(BucketOffset); Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str()); } // Write the offsets table for identifier IDs. BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); RecordData Record; Record.push_back(IDENTIFIER_OFFSET); Record.push_back(IdentifierOffsets.size()); Record.push_back(FirstIdentID - NUM_PREDEF_IDENT_IDS); Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record, data(IdentifierOffsets)); } //===----------------------------------------------------------------------===// // DeclContext's Name Lookup Table Serialization //===----------------------------------------------------------------------===// namespace { // Trait used for the on-disk hash table used in the method pool. class ASTDeclContextNameLookupTrait { ASTWriter &Writer; public: typedef DeclarationName key_type; typedef key_type key_type_ref; typedef DeclContext::lookup_result data_type; typedef const data_type& data_type_ref; explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { } unsigned ComputeHash(DeclarationName Name) { llvm::FoldingSetNodeID ID; ID.AddInteger(Name.getNameKind()); switch (Name.getNameKind()) { case DeclarationName::Identifier: ID.AddString(Name.getAsIdentifierInfo()->getName()); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: ID.AddInteger(serialization::ComputeHash(Name.getObjCSelector())); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: break; case DeclarationName::CXXOperatorName: ID.AddInteger(Name.getCXXOverloadedOperator()); break; case DeclarationName::CXXLiteralOperatorName: ID.AddString(Name.getCXXLiteralIdentifier()->getName()); case DeclarationName::CXXUsingDirective: break; } return ID.ComputeHash(); } std::pair EmitKeyDataLength(raw_ostream& Out, DeclarationName Name, data_type_ref Lookup) { unsigned KeyLen = 1; switch (Name.getNameKind()) { case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXLiteralOperatorName: KeyLen += 4; break; case DeclarationName::CXXOperatorName: KeyLen += 1; break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: break; } clang::io::Emit16(Out, KeyLen); // 2 bytes for num of decls and 4 for each DeclID. unsigned DataLen = 2 + 4 * (Lookup.second - Lookup.first); clang::io::Emit16(Out, DataLen); return std::make_pair(KeyLen, DataLen); } void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) { using namespace clang::io; assert(Name.getNameKind() < 0x100 && "Invalid name kind ?"); Emit8(Out, Name.getNameKind()); switch (Name.getNameKind()) { case DeclarationName::Identifier: Emit32(Out, Writer.getIdentifierRef(Name.getAsIdentifierInfo())); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector())); break; case DeclarationName::CXXOperatorName: assert(Name.getCXXOverloadedOperator() < 0x100 && "Invalid operator ?"); Emit8(Out, Name.getCXXOverloadedOperator()); break; case DeclarationName::CXXLiteralOperatorName: Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier())); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: break; } } void EmitData(raw_ostream& Out, key_type_ref, data_type Lookup, unsigned DataLen) { uint64_t Start = Out.tell(); (void)Start; clang::io::Emit16(Out, Lookup.second - Lookup.first); for (; Lookup.first != Lookup.second; ++Lookup.first) clang::io::Emit32(Out, Writer.GetDeclRef(*Lookup.first)); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } }; } // end anonymous namespace /// \brief Write the block containing all of the declaration IDs /// visible from the given DeclContext. /// /// \returns the offset of the DECL_CONTEXT_VISIBLE block within the /// bitstream, or 0 if no block was written. uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC) { if (DC->getPrimaryContext() != DC) return 0; // Since there is no name lookup into functions or methods, don't bother to // build a visible-declarations table for these entities. if (DC->isFunctionOrMethod()) return 0; // If not in C++, we perform name lookup for the translation unit via the // IdentifierInfo chains, don't bother to build a visible-declarations table. // FIXME: In C++ we need the visible declarations in order to "see" the // friend declarations, is there a way to do this without writing the table ? if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus) return 0; // Serialize the contents of the mapping used for lookup. Note that, // although we have two very different code paths, the serialized // representation is the same for both cases: a declaration name, // followed by a size, followed by references to the visible // declarations that have that name. uint64_t Offset = Stream.GetCurrentBitNo(); StoredDeclsMap *Map = DC->buildLookup(); if (!Map || Map->empty()) return 0; OnDiskChainedHashTableGenerator Generator; ASTDeclContextNameLookupTrait Trait(*this); // Create the on-disk hash table representation. DeclarationName ConversionName; llvm::SmallVector ConversionDecls; for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); D != DEnd; ++D) { DeclarationName Name = D->first; DeclContext::lookup_result Result = D->second.getLookupResult(); if (Result.first != Result.second) { if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { // Hash all conversion function names to the same name. The actual // type information in conversion function name is not used in the // key (since such type information is not stable across different // modules), so the intended effect is to coalesce all of the conversion // functions under a single key. if (!ConversionName) ConversionName = Name; ConversionDecls.append(Result.first, Result.second); continue; } Generator.insert(Name, Result, Trait); } } // Add the conversion functions if (!ConversionDecls.empty()) { Generator.insert(ConversionName, DeclContext::lookup_result(ConversionDecls.begin(), ConversionDecls.end()), Trait); } // Create the on-disk hash table in a buffer. SmallString<4096> LookupTable; uint32_t BucketOffset; { llvm::raw_svector_ostream Out(LookupTable); // Make sure that no bucket is at offset 0 clang::io::Emit32(Out, 0); BucketOffset = Generator.Emit(Out, Trait); } // Write the lookup table RecordData Record; Record.push_back(DECL_CONTEXT_VISIBLE); Record.push_back(BucketOffset); Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record, LookupTable.str()); Stream.EmitRecord(DECL_CONTEXT_VISIBLE, Record); ++NumVisibleDeclContexts; return Offset; } /// \brief Write an UPDATE_VISIBLE block for the given context. /// /// UPDATE_VISIBLE blocks contain the declarations that are added to an existing /// DeclContext in a dependent AST file. As such, they only exist for the TU /// (in C++), for namespaces, and for classes with forward-declared unscoped /// enumeration members (in C++11). void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { StoredDeclsMap *Map = static_cast(DC->getLookupPtr()); if (!Map || Map->empty()) return; OnDiskChainedHashTableGenerator Generator; ASTDeclContextNameLookupTrait Trait(*this); // Create the hash table. for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); D != DEnd; ++D) { DeclarationName Name = D->first; DeclContext::lookup_result Result = D->second.getLookupResult(); // For any name that appears in this table, the results are complete, i.e. // they overwrite results from previous PCHs. Merging is always a mess. if (Result.first != Result.second) Generator.insert(Name, Result, Trait); } // Create the on-disk hash table in a buffer. SmallString<4096> LookupTable; uint32_t BucketOffset; { llvm::raw_svector_ostream Out(LookupTable); // Make sure that no bucket is at offset 0 clang::io::Emit32(Out, 0); BucketOffset = Generator.Emit(Out, Trait); } // Write the lookup table RecordData Record; Record.push_back(UPDATE_VISIBLE); Record.push_back(getDeclID(cast(DC))); Record.push_back(BucketOffset); Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable.str()); } /// \brief Write an FP_PRAGMA_OPTIONS block for the given FPOptions. void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) { RecordData Record; Record.push_back(Opts.fp_contract); Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record); } /// \brief Write an OPENCL_EXTENSIONS block for the given OpenCLOptions. void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) { if (!SemaRef.Context.getLangOpts().OpenCL) return; const OpenCLOptions &Opts = SemaRef.getOpenCLOptions(); RecordData Record; #define OPENCLEXT(nm) Record.push_back(Opts.nm); #include "clang/Basic/OpenCLExtensions.def" Stream.EmitRecord(OPENCL_EXTENSIONS, Record); } void ASTWriter::WriteRedeclarations() { RecordData LocalRedeclChains; SmallVector LocalRedeclsMap; for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) { Decl *First = Redeclarations[I]; assert(First->getPreviousDecl() == 0 && "Not the first declaration?"); Decl *MostRecent = First->getMostRecentDecl(); // If we only have a single declaration, there is no point in storing // a redeclaration chain. if (First == MostRecent) continue; unsigned Offset = LocalRedeclChains.size(); unsigned Size = 0; LocalRedeclChains.push_back(0); // Placeholder for the size. // Collect the set of local redeclarations of this declaration. for (Decl *Prev = MostRecent; Prev != First; Prev = Prev->getPreviousDecl()) { if (!Prev->isFromASTFile()) { AddDeclRef(Prev, LocalRedeclChains); ++Size; } } LocalRedeclChains[Offset] = Size; // Reverse the set of local redeclarations, so that we store them in // order (since we found them in reverse order). std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end()); // Add the mapping from the first ID to the set of local declarations. LocalRedeclarationsInfo Info = { getDeclID(First), Offset }; LocalRedeclsMap.push_back(Info); assert(N == Redeclarations.size() && "Deserialized a declaration we shouldn't have"); } if (LocalRedeclChains.empty()) return; // Sort the local redeclarations map by the first declaration ID, // since the reader will be performing binary searches on this information. llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end()); // Emit the local redeclarations map. using namespace llvm; llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS_MAP)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned AbbrevID = Stream.EmitAbbrev(Abbrev); RecordData Record; Record.push_back(LOCAL_REDECLARATIONS_MAP); Record.push_back(LocalRedeclsMap.size()); Stream.EmitRecordWithBlob(AbbrevID, Record, reinterpret_cast(LocalRedeclsMap.data()), LocalRedeclsMap.size() * sizeof(LocalRedeclarationsInfo)); // Emit the redeclaration chains. Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedeclChains); } void ASTWriter::WriteObjCCategories() { llvm::SmallVector CategoriesMap; RecordData Categories; for (unsigned I = 0, N = ObjCClassesWithCategories.size(); I != N; ++I) { unsigned Size = 0; unsigned StartIndex = Categories.size(); ObjCInterfaceDecl *Class = ObjCClassesWithCategories[I]; // Allocate space for the size. Categories.push_back(0); // Add the categories. for (ObjCCategoryDecl *Cat = Class->getCategoryList(); Cat; Cat = Cat->getNextClassCategory(), ++Size) { assert(getDeclID(Cat) != 0 && "Bogus category"); AddDeclRef(Cat, Categories); } // Update the size. Categories[StartIndex] = Size; // Record this interface -> category map. ObjCCategoriesInfo CatInfo = { getDeclID(Class), StartIndex }; CategoriesMap.push_back(CatInfo); } // Sort the categories map by the definition ID, since the reader will be // performing binary searches on this information. llvm::array_pod_sort(CategoriesMap.begin(), CategoriesMap.end()); // Emit the categories map. using namespace llvm; llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(OBJC_CATEGORIES_MAP)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned AbbrevID = Stream.EmitAbbrev(Abbrev); RecordData Record; Record.push_back(OBJC_CATEGORIES_MAP); Record.push_back(CategoriesMap.size()); Stream.EmitRecordWithBlob(AbbrevID, Record, reinterpret_cast(CategoriesMap.data()), CategoriesMap.size() * sizeof(ObjCCategoriesInfo)); // Emit the category lists. Stream.EmitRecord(OBJC_CATEGORIES, Categories); } void ASTWriter::WriteMergedDecls() { if (!Chain || Chain->MergedDecls.empty()) return; RecordData Record; for (ASTReader::MergedDeclsMap::iterator I = Chain->MergedDecls.begin(), IEnd = Chain->MergedDecls.end(); I != IEnd; ++I) { DeclID CanonID = I->first->isFromASTFile()? I->first->getGlobalID() : getDeclID(I->first); assert(CanonID && "Merged declaration not known?"); Record.push_back(CanonID); Record.push_back(I->second.size()); Record.append(I->second.begin(), I->second.end()); } Stream.EmitRecord(MERGED_DECLARATIONS, Record); } //===----------------------------------------------------------------------===// // General Serialization Routines //===----------------------------------------------------------------------===// /// \brief Write a record containing the given attributes. void ASTWriter::WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record) { Record.push_back(Attrs.size()); for (AttrVec::const_iterator i = Attrs.begin(), e = Attrs.end(); i != e; ++i){ const Attr * A = *i; Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs AddSourceRange(A->getRange(), Record); #include "clang/Serialization/AttrPCHWrite.inc" } } void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) { Record.push_back(Str.size()); Record.insert(Record.end(), Str.begin(), Str.end()); } void ASTWriter::AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record) { Record.push_back(Version.getMajor()); if (llvm::Optional Minor = Version.getMinor()) Record.push_back(*Minor + 1); else Record.push_back(0); if (llvm::Optional Subminor = Version.getSubminor()) Record.push_back(*Subminor + 1); else Record.push_back(0); } /// \brief Note that the identifier II occurs at the given offset /// within the identifier table. void ASTWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) { IdentID ID = IdentifierIDs[II]; // Only store offsets new to this AST file. Other identifier names are looked // up earlier in the chain and thus don't need an offset. if (ID >= FirstIdentID) IdentifierOffsets[ID - FirstIdentID] = Offset; } /// \brief Note that the selector Sel occurs at the given offset /// within the method pool/selector table. void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { unsigned ID = SelectorIDs[Sel]; assert(ID && "Unknown selector"); // Don't record offsets for selectors that are also available in a different // file. if (ID < FirstSelectorID) return; SelectorOffsets[ID - FirstSelectorID] = Offset; } ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) : Stream(Stream), Context(0), PP(0), Chain(0), WritingModule(0), WritingAST(false), ASTHasCompilerErrors(false), FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID), FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID), FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID), FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS), NextSubmoduleID(FirstSubmoduleID), FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID), CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0), NumVisibleDeclContexts(0), NextCXXBaseSpecifiersID(1), DeclParmVarAbbrev(0), DeclContextLexicalAbbrev(0), DeclContextVisibleLookupAbbrev(0), UpdateVisibleAbbrev(0), DeclRefExprAbbrev(0), CharacterLiteralAbbrev(0), DeclRecordAbbrev(0), IntegerLiteralAbbrev(0), DeclTypedefAbbrev(0), DeclVarAbbrev(0), DeclFieldAbbrev(0), DeclEnumAbbrev(0), DeclObjCIvarAbbrev(0) { } ASTWriter::~ASTWriter() { for (FileDeclIDsTy::iterator I = FileDeclIDs.begin(), E = FileDeclIDs.end(); I != E; ++I) delete I->second; } void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, const std::string &OutputFile, Module *WritingModule, StringRef isysroot, bool hasErrors) { WritingAST = true; ASTHasCompilerErrors = hasErrors; // Emit the file header. Stream.Emit((unsigned)'C', 8); Stream.Emit((unsigned)'P', 8); Stream.Emit((unsigned)'C', 8); Stream.Emit((unsigned)'H', 8); WriteBlockInfoBlock(); Context = &SemaRef.Context; PP = &SemaRef.PP; this->WritingModule = WritingModule; WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, WritingModule); Context = 0; PP = 0; this->WritingModule = 0; WritingAST = false; } template static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec, ASTWriter::RecordData &Record) { for (typename Vector::iterator I = Vec.begin(0, true), E = Vec.end(); I != E; ++I) { Writer.AddDeclRef(*I, Record); } } void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, StringRef isysroot, const std::string &OutputFile, Module *WritingModule) { using namespace llvm; // Make sure that the AST reader knows to finalize itself. if (Chain) Chain->finalizeForWriting(); ASTContext &Context = SemaRef.Context; Preprocessor &PP = SemaRef.PP; // Set up predefined declaration IDs. DeclIDs[Context.getTranslationUnitDecl()] = PREDEF_DECL_TRANSLATION_UNIT_ID; if (Context.ObjCIdDecl) DeclIDs[Context.ObjCIdDecl] = PREDEF_DECL_OBJC_ID_ID; if (Context.ObjCSelDecl) DeclIDs[Context.ObjCSelDecl] = PREDEF_DECL_OBJC_SEL_ID; if (Context.ObjCClassDecl) DeclIDs[Context.ObjCClassDecl] = PREDEF_DECL_OBJC_CLASS_ID; if (Context.ObjCProtocolClassDecl) DeclIDs[Context.ObjCProtocolClassDecl] = PREDEF_DECL_OBJC_PROTOCOL_ID; if (Context.Int128Decl) DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID; if (Context.UInt128Decl) DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID; if (Context.ObjCInstanceTypeDecl) DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID; if (!Chain) { // Make sure that we emit IdentifierInfos (and any attached // declarations) for builtins. We don't need to do this when we're // emitting chained PCH files, because all of the builtins will be // in the original PCH file. // FIXME: Modules won't like this at all. IdentifierTable &Table = PP.getIdentifierTable(); SmallVector BuiltinNames; Context.BuiltinInfo.GetBuiltinNames(BuiltinNames, Context.getLangOpts().NoBuiltin); for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I) getIdentifierRef(&Table.get(BuiltinNames[I])); } // If there are any out-of-date identifiers, bring them up to date. if (ExternalPreprocessorSource *ExtSource = PP.getExternalSource()) { for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), IDEnd = PP.getIdentifierTable().end(); ID != IDEnd; ++ID) if (ID->second->isOutOfDate()) ExtSource->updateOutOfDateIdentifier(*ID->second); } // Build a record containing all of the tentative definitions in this file, in // TentativeDefinitions order. Generally, this record will be empty for // headers. RecordData TentativeDefinitions; AddLazyVectorDecls(*this, SemaRef.TentativeDefinitions, TentativeDefinitions); // Build a record containing all of the file scoped decls in this file. RecordData UnusedFileScopedDecls; AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls, UnusedFileScopedDecls); // Build a record containing all of the delegating constructors we still need // to resolve. RecordData DelegatingCtorDecls; AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls); // Write the set of weak, undeclared identifiers. We always write the // entire table, since later PCH files in a PCH chain are only interested in // the results at the end of the chain. RecordData WeakUndeclaredIdentifiers; if (!SemaRef.WeakUndeclaredIdentifiers.empty()) { for (llvm::DenseMap::iterator I = SemaRef.WeakUndeclaredIdentifiers.begin(), E = SemaRef.WeakUndeclaredIdentifiers.end(); I != E; ++I) { AddIdentifierRef(I->first, WeakUndeclaredIdentifiers); AddIdentifierRef(I->second.getAlias(), WeakUndeclaredIdentifiers); AddSourceLocation(I->second.getLocation(), WeakUndeclaredIdentifiers); WeakUndeclaredIdentifiers.push_back(I->second.getUsed()); } } // Build a record containing all of the locally-scoped external // declarations in this header file. Generally, this record will be // empty. RecordData LocallyScopedExternalDecls; // FIXME: This is filling in the AST file in densemap order which is // nondeterminstic! for (llvm::DenseMap::iterator TD = SemaRef.LocallyScopedExternalDecls.begin(), TDEnd = SemaRef.LocallyScopedExternalDecls.end(); TD != TDEnd; ++TD) { if (!TD->second->isFromASTFile()) AddDeclRef(TD->second, LocallyScopedExternalDecls); } // Build a record containing all of the ext_vector declarations. RecordData ExtVectorDecls; AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls); // Build a record containing all of the VTable uses information. RecordData VTableUses; if (!SemaRef.VTableUses.empty()) { for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) { AddDeclRef(SemaRef.VTableUses[I].first, VTableUses); AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses); VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]); } } // Build a record containing all of dynamic classes declarations. RecordData DynamicClasses; AddLazyVectorDecls(*this, SemaRef.DynamicClasses, DynamicClasses); // Build a record containing all of pending implicit instantiations. RecordData PendingInstantiations; for (std::deque::iterator I = SemaRef.PendingInstantiations.begin(), N = SemaRef.PendingInstantiations.end(); I != N; ++I) { AddDeclRef(I->first, PendingInstantiations); AddSourceLocation(I->second, PendingInstantiations); } assert(SemaRef.PendingLocalImplicitInstantiations.empty() && "There are local ones at end of translation unit!"); // Build a record containing some declaration references. RecordData SemaDeclRefs; if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) { AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs); AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs); } RecordData CUDASpecialDeclRefs; if (Context.getcudaConfigureCallDecl()) { AddDeclRef(Context.getcudaConfigureCallDecl(), CUDASpecialDeclRefs); } // Build a record containing all of the known namespaces. RecordData KnownNamespaces; for (llvm::DenseMap::iterator I = SemaRef.KnownNamespaces.begin(), IEnd = SemaRef.KnownNamespaces.end(); I != IEnd; ++I) { if (!I->second) AddDeclRef(I->first, KnownNamespaces); } // Write the remaining AST contents. RecordData Record; Stream.EnterSubblock(AST_BLOCK_ID, 5); WriteMetadata(Context, isysroot, OutputFile); WriteLanguageOptions(Context.getLangOpts()); if (StatCalls && isysroot.empty()) WriteStatCache(*StatCalls); // Create a lexical update block containing all of the declarations in the // translation unit that do not come from other AST files. const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); SmallVector NewGlobalDecls; for (DeclContext::decl_iterator I = TU->noload_decls_begin(), E = TU->noload_decls_end(); I != E; ++I) { if (!(*I)->isFromASTFile()) NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I))); } llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev(); Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(Abv); Record.clear(); Record.push_back(TU_UPDATE_LEXICAL); Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, data(NewGlobalDecls)); // And a visible updates block for the translation unit. Abv = new llvm::BitCodeAbbrev(); Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 32)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv); WriteDeclContextVisibleUpdate(TU); // If the translation unit has an anonymous namespace, and we don't already // have an update block for it, write it as an update block. if (NamespaceDecl *NS = TU->getAnonymousNamespace()) { ASTWriter::UpdateRecord &Record = DeclUpdates[TU]; if (Record.empty()) { Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE); Record.push_back(reinterpret_cast(NS)); } } // Resolve any declaration pointers within the declaration updates block. ResolveDeclUpdatesBlocks(); // Form the record of special types. RecordData SpecialTypes; AddTypeRef(Context.getBuiltinVaListType(), SpecialTypes); AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes); AddTypeRef(Context.getFILEType(), SpecialTypes); AddTypeRef(Context.getjmp_bufType(), SpecialTypes); AddTypeRef(Context.getsigjmp_bufType(), SpecialTypes); AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes); AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes); AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes); AddTypeRef(Context.getucontext_tType(), SpecialTypes); // Keep writing types and declarations until all types and // declarations have been written. Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); WriteDeclsBlockAbbrevs(); for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(), E = DeclsToRewrite.end(); I != E; ++I) DeclTypesToEmit.push(const_cast(*I)); while (!DeclTypesToEmit.empty()) { DeclOrType DOT = DeclTypesToEmit.front(); DeclTypesToEmit.pop(); if (DOT.isType()) WriteType(DOT.getType()); else WriteDecl(Context, DOT.getDecl()); } Stream.ExitBlock(); WriteFileDeclIDsMap(); WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); if (Chain) { // Write the mapping information describing our module dependencies and how // each of those modules were mapped into our own offset/ID space, so that // the reader can build the appropriate mapping to its own offset/ID space. // The map consists solely of a blob with the following format: // *(module-name-len:i16 module-name:len*i8 // source-location-offset:i32 // identifier-id:i32 // preprocessed-entity-id:i32 // macro-definition-id:i32 // submodule-id:i32 // selector-id:i32 // declaration-id:i32 // c++-base-specifiers-id:i32 // type-id:i32) // llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev); SmallString<2048> Buffer; { llvm::raw_svector_ostream Out(Buffer); for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(), MEnd = Chain->ModuleMgr.end(); M != MEnd; ++M) { StringRef FileName = (*M)->FileName; io::Emit16(Out, FileName.size()); Out.write(FileName.data(), FileName.size()); io::Emit32(Out, (*M)->SLocEntryBaseOffset); io::Emit32(Out, (*M)->BaseIdentifierID); io::Emit32(Out, (*M)->BasePreprocessedEntityID); io::Emit32(Out, (*M)->BaseSubmoduleID); io::Emit32(Out, (*M)->BaseSelectorID); io::Emit32(Out, (*M)->BaseDeclID); io::Emit32(Out, (*M)->BaseTypeIndex); } } Record.clear(); Record.push_back(MODULE_OFFSET_MAP); Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record, Buffer.data(), Buffer.size()); } WritePreprocessor(PP, WritingModule != 0); WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot); WriteSelectors(SemaRef); WriteReferencedSelectorsPool(SemaRef); WriteIdentifierTable(PP, SemaRef.IdResolver, WritingModule != 0); WriteFPPragmaOptions(SemaRef.getFPOptions()); WriteOpenCLExtensions(SemaRef); WriteTypeDeclOffsets(); WritePragmaDiagnosticMappings(Context.getDiagnostics()); WriteCXXBaseSpecifiersOffsets(); // If we're emitting a module, write out the submodule information. if (WritingModule) WriteSubmodules(WritingModule); Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes); // Write the record containing external, unnamed definitions. if (!ExternalDefinitions.empty()) Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions); // Write the record containing tentative definitions. if (!TentativeDefinitions.empty()) Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions); // Write the record containing unused file scoped decls. if (!UnusedFileScopedDecls.empty()) Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls); // Write the record containing weak undeclared identifiers. if (!WeakUndeclaredIdentifiers.empty()) Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS, WeakUndeclaredIdentifiers); // Write the record containing locally-scoped external definitions. if (!LocallyScopedExternalDecls.empty()) Stream.EmitRecord(LOCALLY_SCOPED_EXTERNAL_DECLS, LocallyScopedExternalDecls); // Write the record containing ext_vector type names. if (!ExtVectorDecls.empty()) Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls); // Write the record containing VTable uses information. if (!VTableUses.empty()) Stream.EmitRecord(VTABLE_USES, VTableUses); // Write the record containing dynamic classes declarations. if (!DynamicClasses.empty()) Stream.EmitRecord(DYNAMIC_CLASSES, DynamicClasses); // Write the record containing pending implicit instantiations. if (!PendingInstantiations.empty()) Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations); // Write the record containing declaration references of Sema. if (!SemaDeclRefs.empty()) Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs); // Write the record containing CUDA-specific declaration references. if (!CUDASpecialDeclRefs.empty()) Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs); // Write the delegating constructors. if (!DelegatingCtorDecls.empty()) Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls); // Write the known namespaces. if (!KnownNamespaces.empty()) Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces); // Write the visible updates to DeclContexts. for (llvm::SmallPtrSet::iterator I = UpdatedDeclContexts.begin(), E = UpdatedDeclContexts.end(); I != E; ++I) WriteDeclContextVisibleUpdate(*I); if (!WritingModule) { // Write the submodules that were imported, if any. RecordData ImportedModules; for (ASTContext::import_iterator I = Context.local_import_begin(), IEnd = Context.local_import_end(); I != IEnd; ++I) { assert(SubmoduleIDs.find(I->getImportedModule()) != SubmoduleIDs.end()); ImportedModules.push_back(SubmoduleIDs[I->getImportedModule()]); } if (!ImportedModules.empty()) { // Sort module IDs. llvm::array_pod_sort(ImportedModules.begin(), ImportedModules.end()); // Unique module IDs. ImportedModules.erase(std::unique(ImportedModules.begin(), ImportedModules.end()), ImportedModules.end()); Stream.EmitRecord(IMPORTED_MODULES, ImportedModules); } } WriteDeclUpdatesBlocks(); WriteDeclReplacementsBlock(); WriteMergedDecls(); WriteRedeclarations(); WriteObjCCategories(); // Some simple statistics Record.clear(); Record.push_back(NumStatements); Record.push_back(NumMacros); Record.push_back(NumLexicalDeclContexts); Record.push_back(NumVisibleDeclContexts); Stream.EmitRecord(STATISTICS, Record); Stream.ExitBlock(); } /// \brief Go through the declaration update blocks and resolve declaration /// pointers into declaration IDs. void ASTWriter::ResolveDeclUpdatesBlocks() { for (DeclUpdateMap::iterator I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) { const Decl *D = I->first; UpdateRecord &URec = I->second; if (isRewritten(D)) continue; // The decl will be written completely unsigned Idx = 0, N = URec.size(); while (Idx < N) { switch ((DeclUpdateKind)URec[Idx++]) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: URec[Idx] = GetDeclRef(reinterpret_cast(URec[Idx])); ++Idx; break; case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: ++Idx; break; } } } } void ASTWriter::WriteDeclUpdatesBlocks() { if (DeclUpdates.empty()) return; RecordData OffsetsRecord; Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); for (DeclUpdateMap::iterator I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) { const Decl *D = I->first; UpdateRecord &URec = I->second; if (isRewritten(D)) continue; // The decl will be written completely,no need to store updates. uint64_t Offset = Stream.GetCurrentBitNo(); Stream.EmitRecord(DECL_UPDATES, URec); OffsetsRecord.push_back(GetDeclRef(D)); OffsetsRecord.push_back(Offset); } Stream.ExitBlock(); Stream.EmitRecord(DECL_UPDATE_OFFSETS, OffsetsRecord); } void ASTWriter::WriteDeclReplacementsBlock() { if (ReplacedDecls.empty()) return; RecordData Record; for (SmallVector::iterator I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) { Record.push_back(I->ID); Record.push_back(I->Offset); Record.push_back(I->Loc); } Stream.EmitRecord(DECL_REPLACEMENTS, Record); } void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record) { Record.push_back(Loc.getRawEncoding()); } void ASTWriter::AddSourceRange(SourceRange Range, RecordDataImpl &Record) { AddSourceLocation(Range.getBegin(), Record); AddSourceLocation(Range.getEnd(), Record); } void ASTWriter::AddAPInt(const llvm::APInt &Value, RecordDataImpl &Record) { Record.push_back(Value.getBitWidth()); const uint64_t *Words = Value.getRawData(); Record.append(Words, Words + Value.getNumWords()); } void ASTWriter::AddAPSInt(const llvm::APSInt &Value, RecordDataImpl &Record) { Record.push_back(Value.isUnsigned()); AddAPInt(Value, Record); } void ASTWriter::AddAPFloat(const llvm::APFloat &Value, RecordDataImpl &Record) { AddAPInt(Value.bitcastToAPInt(), Record); } void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record) { Record.push_back(getIdentifierRef(II)); } IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { if (II == 0) return 0; IdentID &ID = IdentifierIDs[II]; if (ID == 0) ID = NextIdentID++; return ID; } void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) { Record.push_back(getSelectorRef(SelRef)); } SelectorID ASTWriter::getSelectorRef(Selector Sel) { if (Sel.getAsOpaquePtr() == 0) { return 0; } SelectorID &SID = SelectorIDs[Sel]; if (SID == 0 && Chain) { // This might trigger a ReadSelector callback, which will set the ID for // this selector. Chain->LoadSelector(Sel); } if (SID == 0) { SID = NextSelectorID++; } return SID; } void ASTWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordDataImpl &Record) { AddDeclRef(Temp->getDestructor(), Record); } void ASTWriter::AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases, CXXBaseSpecifier const *BasesEnd, RecordDataImpl &Record) { assert(Bases != BasesEnd && "Empty base-specifier sets are not recorded"); CXXBaseSpecifiersToWrite.push_back( QueuedCXXBaseSpecifiers(NextCXXBaseSpecifiersID, Bases, BasesEnd)); Record.push_back(NextCXXBaseSpecifiersID++); } void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, const TemplateArgumentLocInfo &Arg, RecordDataImpl &Record) { switch (Kind) { case TemplateArgument::Expression: AddStmt(Arg.getAsExpr()); break; case TemplateArgument::Type: AddTypeSourceInfo(Arg.getAsTypeSourceInfo(), Record); break; case TemplateArgument::Template: AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record); AddSourceLocation(Arg.getTemplateNameLoc(), Record); break; case TemplateArgument::TemplateExpansion: AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record); AddSourceLocation(Arg.getTemplateNameLoc(), Record); AddSourceLocation(Arg.getTemplateEllipsisLoc(), Record); break; case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: case TemplateArgument::Pack: break; } } void ASTWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, RecordDataImpl &Record) { AddTemplateArgument(Arg.getArgument(), Record); if (Arg.getArgument().getKind() == TemplateArgument::Expression) { bool InfoHasSameExpr = Arg.getArgument().getAsExpr() == Arg.getLocInfo().getAsExpr(); Record.push_back(InfoHasSameExpr); if (InfoHasSameExpr) return; // Avoid storing the same expr twice. } AddTemplateArgumentLocInfo(Arg.getArgument().getKind(), Arg.getLocInfo(), Record); } void ASTWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordDataImpl &Record) { if (TInfo == 0) { AddTypeRef(QualType(), Record); return; } AddTypeLoc(TInfo->getTypeLoc(), Record); } void ASTWriter::AddTypeLoc(TypeLoc TL, RecordDataImpl &Record) { AddTypeRef(TL.getType(), Record); TypeLocWriter TLW(*this, Record); for (; !TL.isNull(); TL = TL.getNextTypeLoc()) TLW.Visit(TL); } void ASTWriter::AddTypeRef(QualType T, RecordDataImpl &Record) { Record.push_back(GetOrCreateTypeID(T)); } TypeID ASTWriter::GetOrCreateTypeID( QualType T) { return MakeTypeID(*Context, T, std::bind1st(std::mem_fun(&ASTWriter::GetOrCreateTypeIdx), this)); } TypeID ASTWriter::getTypeID(QualType T) const { return MakeTypeID(*Context, T, std::bind1st(std::mem_fun(&ASTWriter::getTypeIdx), this)); } TypeIdx ASTWriter::GetOrCreateTypeIdx(QualType T) { if (T.isNull()) return TypeIdx(); assert(!T.getLocalFastQualifiers()); TypeIdx &Idx = TypeIdxs[T]; if (Idx.getIndex() == 0) { // We haven't seen this type before. Assign it a new ID and put it // into the queue of types to emit. Idx = TypeIdx(NextTypeID++); DeclTypesToEmit.push(T); } return Idx; } TypeIdx ASTWriter::getTypeIdx(QualType T) const { if (T.isNull()) return TypeIdx(); assert(!T.getLocalFastQualifiers()); TypeIdxMap::const_iterator I = TypeIdxs.find(T); assert(I != TypeIdxs.end() && "Type not emitted!"); return I->second; } void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) { Record.push_back(GetDeclRef(D)); } DeclID ASTWriter::GetDeclRef(const Decl *D) { assert(WritingAST && "Cannot request a declaration ID before AST writing"); if (D == 0) { return 0; } // If D comes from an AST file, its declaration ID is already known and // fixed. if (D->isFromASTFile()) return D->getGlobalID(); assert(!(reinterpret_cast(D) & 0x01) && "Invalid decl pointer"); DeclID &ID = DeclIDs[D]; if (ID == 0) { // We haven't seen this declaration before. Give it a new ID and // enqueue it in the list of declarations to emit. ID = NextDeclID++; DeclTypesToEmit.push(const_cast(D)); } return ID; } DeclID ASTWriter::getDeclID(const Decl *D) { if (D == 0) return 0; // If D comes from an AST file, its declaration ID is already known and // fixed. if (D->isFromASTFile()) return D->getGlobalID(); assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!"); return DeclIDs[D]; } static inline bool compLocDecl(std::pair L, std::pair R) { return L.first < R.first; } void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) { assert(ID); assert(D); SourceLocation Loc = D->getLocation(); if (Loc.isInvalid()) return; // We only keep track of the file-level declarations of each file. if (!D->getLexicalDeclContext()->isFileContext()) return; // FIXME: ParmVarDecls that are part of a function type of a parameter of // a function/objc method, should not have TU as lexical context. if (isa(D)) return; SourceManager &SM = Context->getSourceManager(); SourceLocation FileLoc = SM.getFileLoc(Loc); assert(SM.isLocalSourceLocation(FileLoc)); FileID FID; unsigned Offset; llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc); if (FID.isInvalid()) return; const SrcMgr::SLocEntry *Entry = &SM.getSLocEntry(FID); assert(Entry->isFile()); DeclIDInFileInfo *&Info = FileDeclIDs[Entry]; if (!Info) Info = new DeclIDInFileInfo(); std::pair LocDecl(Offset, ID); LocDeclIDsTy &Decls = Info->DeclIDs; if (Decls.empty() || Decls.back().first <= Offset) { Decls.push_back(LocDecl); return; } LocDeclIDsTy::iterator I = std::upper_bound(Decls.begin(), Decls.end(), LocDecl, compLocDecl); Decls.insert(I, LocDecl); } void ASTWriter::AddDeclarationName(DeclarationName Name, RecordDataImpl &Record) { // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc. Record.push_back(Name.getNameKind()); switch (Name.getNameKind()) { case DeclarationName::Identifier: AddIdentifierRef(Name.getAsIdentifierInfo(), Record); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: AddSelectorRef(Name.getObjCSelector(), Record); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: AddTypeRef(Name.getCXXNameType(), Record); break; case DeclarationName::CXXOperatorName: Record.push_back(Name.getCXXOverloadedOperator()); break; case DeclarationName::CXXLiteralOperatorName: AddIdentifierRef(Name.getCXXLiteralIdentifier(), Record); break; case DeclarationName::CXXUsingDirective: // No extra data to emit break; } } void ASTWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc, DeclarationName Name, RecordDataImpl &Record) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: AddTypeSourceInfo(DNLoc.NamedType.TInfo, Record); break; case DeclarationName::CXXOperatorName: AddSourceLocation( SourceLocation::getFromRawEncoding(DNLoc.CXXOperatorName.BeginOpNameLoc), Record); AddSourceLocation( SourceLocation::getFromRawEncoding(DNLoc.CXXOperatorName.EndOpNameLoc), Record); break; case DeclarationName::CXXLiteralOperatorName: AddSourceLocation( SourceLocation::getFromRawEncoding(DNLoc.CXXLiteralOperatorName.OpNameLoc), Record); break; case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: break; } } void ASTWriter::AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo, RecordDataImpl &Record) { AddDeclarationName(NameInfo.getName(), Record); AddSourceLocation(NameInfo.getLoc(), Record); AddDeclarationNameLoc(NameInfo.getInfo(), NameInfo.getName(), Record); } void ASTWriter::AddQualifierInfo(const QualifierInfo &Info, RecordDataImpl &Record) { AddNestedNameSpecifierLoc(Info.QualifierLoc, Record); Record.push_back(Info.NumTemplParamLists); for (unsigned i=0, e=Info.NumTemplParamLists; i != e; ++i) AddTemplateParameterList(Info.TemplParamLists[i], Record); } void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordDataImpl &Record) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. SmallVector NestedNames; // Push each of the NNS's onto a stack for serialization in reverse order. while (NNS) { NestedNames.push_back(NNS); NNS = NNS->getPrefix(); } Record.push_back(NestedNames.size()); while(!NestedNames.empty()) { NNS = NestedNames.pop_back_val(); NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); Record.push_back(Kind); switch (Kind) { case NestedNameSpecifier::Identifier: AddIdentifierRef(NNS->getAsIdentifier(), Record); break; case NestedNameSpecifier::Namespace: AddDeclRef(NNS->getAsNamespace(), Record); break; case NestedNameSpecifier::NamespaceAlias: AddDeclRef(NNS->getAsNamespaceAlias(), Record); break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: AddTypeRef(QualType(NNS->getAsType(), 0), Record); Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate); break; case NestedNameSpecifier::Global: // Don't need to write an associated value. break; } } } void ASTWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, RecordDataImpl &Record) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. SmallVector NestedNames; // Push each of the nested-name-specifiers's onto a stack for // serialization in reverse order. while (NNS) { NestedNames.push_back(NNS); NNS = NNS.getPrefix(); } Record.push_back(NestedNames.size()); while(!NestedNames.empty()) { NNS = NestedNames.pop_back_val(); NestedNameSpecifier::SpecifierKind Kind = NNS.getNestedNameSpecifier()->getKind(); Record.push_back(Kind); switch (Kind) { case NestedNameSpecifier::Identifier: AddIdentifierRef(NNS.getNestedNameSpecifier()->getAsIdentifier(), Record); AddSourceRange(NNS.getLocalSourceRange(), Record); break; case NestedNameSpecifier::Namespace: AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespace(), Record); AddSourceRange(NNS.getLocalSourceRange(), Record); break; case NestedNameSpecifier::NamespaceAlias: AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(), Record); AddSourceRange(NNS.getLocalSourceRange(), Record); break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate); AddTypeLoc(NNS.getTypeLoc(), Record); AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record); break; case NestedNameSpecifier::Global: AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record); break; } } } void ASTWriter::AddTemplateName(TemplateName Name, RecordDataImpl &Record) { TemplateName::NameKind Kind = Name.getKind(); Record.push_back(Kind); switch (Kind) { case TemplateName::Template: AddDeclRef(Name.getAsTemplateDecl(), Record); break; case TemplateName::OverloadedTemplate: { OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate(); Record.push_back(OvT->size()); for (OverloadedTemplateStorage::iterator I = OvT->begin(), E = OvT->end(); I != E; ++I) AddDeclRef(*I, Record); break; } case TemplateName::QualifiedTemplate: { QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName(); AddNestedNameSpecifier(QualT->getQualifier(), Record); Record.push_back(QualT->hasTemplateKeyword()); AddDeclRef(QualT->getTemplateDecl(), Record); break; } case TemplateName::DependentTemplate: { DependentTemplateName *DepT = Name.getAsDependentTemplateName(); AddNestedNameSpecifier(DepT->getQualifier(), Record); Record.push_back(DepT->isIdentifier()); if (DepT->isIdentifier()) AddIdentifierRef(DepT->getIdentifier(), Record); else Record.push_back(DepT->getOperator()); break; } case TemplateName::SubstTemplateTemplateParm: { SubstTemplateTemplateParmStorage *subst = Name.getAsSubstTemplateTemplateParm(); AddDeclRef(subst->getParameter(), Record); AddTemplateName(subst->getReplacement(), Record); break; } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *SubstPack = Name.getAsSubstTemplateTemplateParmPack(); AddDeclRef(SubstPack->getParameterPack(), Record); AddTemplateArgument(SubstPack->getArgumentPack(), Record); break; } } } void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg, RecordDataImpl &Record) { Record.push_back(Arg.getKind()); switch (Arg.getKind()) { case TemplateArgument::Null: break; case TemplateArgument::Type: AddTypeRef(Arg.getAsType(), Record); break; case TemplateArgument::Declaration: AddDeclRef(Arg.getAsDecl(), Record); break; case TemplateArgument::Integral: AddAPSInt(*Arg.getAsIntegral(), Record); AddTypeRef(Arg.getIntegralType(), Record); break; case TemplateArgument::Template: AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record); break; case TemplateArgument::TemplateExpansion: AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record); if (llvm::Optional NumExpansions = Arg.getNumTemplateExpansions()) Record.push_back(*NumExpansions + 1); else Record.push_back(0); break; case TemplateArgument::Expression: AddStmt(Arg.getAsExpr()); break; case TemplateArgument::Pack: Record.push_back(Arg.pack_size()); for (TemplateArgument::pack_iterator I=Arg.pack_begin(), E=Arg.pack_end(); I != E; ++I) AddTemplateArgument(*I, Record); break; } } void ASTWriter::AddTemplateParameterList(const TemplateParameterList *TemplateParams, RecordDataImpl &Record) { assert(TemplateParams && "No TemplateParams!"); AddSourceLocation(TemplateParams->getTemplateLoc(), Record); AddSourceLocation(TemplateParams->getLAngleLoc(), Record); AddSourceLocation(TemplateParams->getRAngleLoc(), Record); Record.push_back(TemplateParams->size()); for (TemplateParameterList::const_iterator P = TemplateParams->begin(), PEnd = TemplateParams->end(); P != PEnd; ++P) AddDeclRef(*P, Record); } /// \brief Emit a template argument list. void ASTWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs, RecordDataImpl &Record) { assert(TemplateArgs && "No TemplateArgs!"); Record.push_back(TemplateArgs->size()); for (int i=0, e = TemplateArgs->size(); i != e; ++i) AddTemplateArgument(TemplateArgs->get(i), Record); } void ASTWriter::AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record) { Record.push_back(Set.size()); for (UnresolvedSetImpl::const_iterator I = Set.begin(), E = Set.end(); I != E; ++I) { AddDeclRef(I.getDecl(), Record); Record.push_back(I.getAccess()); } } void ASTWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, RecordDataImpl &Record) { Record.push_back(Base.isVirtual()); Record.push_back(Base.isBaseOfClass()); Record.push_back(Base.getAccessSpecifierAsWritten()); Record.push_back(Base.getInheritConstructors()); AddTypeSourceInfo(Base.getTypeSourceInfo(), Record); AddSourceRange(Base.getSourceRange(), Record); AddSourceLocation(Base.isPackExpansion()? Base.getEllipsisLoc() : SourceLocation(), Record); } void ASTWriter::FlushCXXBaseSpecifiers() { RecordData Record; for (unsigned I = 0, N = CXXBaseSpecifiersToWrite.size(); I != N; ++I) { Record.clear(); // Record the offset of this base-specifier set. unsigned Index = CXXBaseSpecifiersToWrite[I].ID - 1; if (Index == CXXBaseSpecifiersOffsets.size()) CXXBaseSpecifiersOffsets.push_back(Stream.GetCurrentBitNo()); else { if (Index > CXXBaseSpecifiersOffsets.size()) CXXBaseSpecifiersOffsets.resize(Index + 1); CXXBaseSpecifiersOffsets[Index] = Stream.GetCurrentBitNo(); } const CXXBaseSpecifier *B = CXXBaseSpecifiersToWrite[I].Bases, *BEnd = CXXBaseSpecifiersToWrite[I].BasesEnd; Record.push_back(BEnd - B); for (; B != BEnd; ++B) AddCXXBaseSpecifier(*B, Record); Stream.EmitRecord(serialization::DECL_CXX_BASE_SPECIFIERS, Record); // Flush any expressions that were written as part of the base specifiers. FlushStmts(); } CXXBaseSpecifiersToWrite.clear(); } void ASTWriter::AddCXXCtorInitializers( const CXXCtorInitializer * const *CtorInitializers, unsigned NumCtorInitializers, RecordDataImpl &Record) { Record.push_back(NumCtorInitializers); for (unsigned i=0; i != NumCtorInitializers; ++i) { const CXXCtorInitializer *Init = CtorInitializers[i]; if (Init->isBaseInitializer()) { Record.push_back(CTOR_INITIALIZER_BASE); AddTypeSourceInfo(Init->getTypeSourceInfo(), Record); Record.push_back(Init->isBaseVirtual()); } else if (Init->isDelegatingInitializer()) { Record.push_back(CTOR_INITIALIZER_DELEGATING); AddTypeSourceInfo(Init->getTypeSourceInfo(), Record); } else if (Init->isMemberInitializer()){ Record.push_back(CTOR_INITIALIZER_MEMBER); AddDeclRef(Init->getMember(), Record); } else { Record.push_back(CTOR_INITIALIZER_INDIRECT_MEMBER); AddDeclRef(Init->getIndirectMember(), Record); } AddSourceLocation(Init->getMemberLocation(), Record); AddStmt(Init->getInit()); AddSourceLocation(Init->getLParenLoc(), Record); AddSourceLocation(Init->getRParenLoc(), Record); Record.push_back(Init->isWritten()); if (Init->isWritten()) { Record.push_back(Init->getSourceOrder()); } else { Record.push_back(Init->getNumArrayIndices()); for (unsigned i=0, e=Init->getNumArrayIndices(); i != e; ++i) AddDeclRef(Init->getArrayIndex(i), Record); } } } void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record) { assert(D->DefinitionData); struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData; Record.push_back(Data.IsLambda); Record.push_back(Data.UserDeclaredConstructor); Record.push_back(Data.UserDeclaredCopyConstructor); Record.push_back(Data.UserDeclaredMoveConstructor); Record.push_back(Data.UserDeclaredCopyAssignment); Record.push_back(Data.UserDeclaredMoveAssignment); Record.push_back(Data.UserDeclaredDestructor); Record.push_back(Data.Aggregate); Record.push_back(Data.PlainOldData); Record.push_back(Data.Empty); Record.push_back(Data.Polymorphic); Record.push_back(Data.Abstract); Record.push_back(Data.IsStandardLayout); Record.push_back(Data.HasNoNonEmptyBases); Record.push_back(Data.HasPrivateFields); Record.push_back(Data.HasProtectedFields); Record.push_back(Data.HasPublicFields); Record.push_back(Data.HasMutableFields); Record.push_back(Data.HasOnlyCMembers); Record.push_back(Data.HasTrivialDefaultConstructor); Record.push_back(Data.HasConstexprNonCopyMoveConstructor); Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr); Record.push_back(Data.DefaultedCopyConstructorIsConstexpr); Record.push_back(Data.DefaultedMoveConstructorIsConstexpr); Record.push_back(Data.HasConstexprDefaultConstructor); Record.push_back(Data.HasConstexprCopyConstructor); Record.push_back(Data.HasConstexprMoveConstructor); Record.push_back(Data.HasTrivialCopyConstructor); Record.push_back(Data.HasTrivialMoveConstructor); Record.push_back(Data.HasTrivialCopyAssignment); Record.push_back(Data.HasTrivialMoveAssignment); Record.push_back(Data.HasTrivialDestructor); Record.push_back(Data.HasIrrelevantDestructor); Record.push_back(Data.HasNonLiteralTypeFieldsOrBases); Record.push_back(Data.ComputedVisibleConversions); Record.push_back(Data.UserProvidedDefaultConstructor); Record.push_back(Data.DeclaredDefaultConstructor); Record.push_back(Data.DeclaredCopyConstructor); Record.push_back(Data.DeclaredMoveConstructor); Record.push_back(Data.DeclaredCopyAssignment); Record.push_back(Data.DeclaredMoveAssignment); Record.push_back(Data.DeclaredDestructor); Record.push_back(Data.FailedImplicitMoveConstructor); Record.push_back(Data.FailedImplicitMoveAssignment); // IsLambda bit is already saved. Record.push_back(Data.NumBases); if (Data.NumBases > 0) AddCXXBaseSpecifiersRef(Data.getBases(), Data.getBases() + Data.NumBases, Record); // FIXME: Make VBases lazily computed when needed to avoid storing them. Record.push_back(Data.NumVBases); if (Data.NumVBases > 0) AddCXXBaseSpecifiersRef(Data.getVBases(), Data.getVBases() + Data.NumVBases, Record); AddUnresolvedSet(Data.Conversions, Record); AddUnresolvedSet(Data.VisibleConversions, Record); // Data.Definition is the owning decl, no need to write it. AddDeclRef(Data.FirstFriend, Record); // Add lambda-specific data. if (Data.IsLambda) { CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData(); Record.push_back(Lambda.Dependent); Record.push_back(Lambda.NumCaptures); Record.push_back(Lambda.NumExplicitCaptures); Record.push_back(Lambda.ManglingNumber); AddDeclRef(Lambda.ContextDecl, Record); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { LambdaExpr::Capture &Capture = Lambda.Captures[I]; AddSourceLocation(Capture.getLocation(), Record); Record.push_back(Capture.isImplicit()); Record.push_back(Capture.getCaptureKind()); // FIXME: stable! VarDecl *Var = Capture.capturesVariable()? Capture.getCapturedVar() : 0; AddDeclRef(Var, Record); AddSourceLocation(Capture.isPackExpansion()? Capture.getEllipsisLoc() : SourceLocation(), Record); } } } void ASTWriter::ReaderInitialized(ASTReader *Reader) { assert(Reader && "Cannot remove chain"); assert((!Chain || Chain == Reader) && "Cannot replace chain"); assert(FirstDeclID == NextDeclID && FirstTypeID == NextTypeID && FirstIdentID == NextIdentID && FirstSubmoduleID == NextSubmoduleID && FirstSelectorID == NextSelectorID && "Setting chain after writing has started."); Chain = Reader; FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls(); FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes(); FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers(); FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules(); FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors(); NextDeclID = FirstDeclID; NextTypeID = FirstTypeID; NextIdentID = FirstIdentID; NextSelectorID = FirstSelectorID; NextSubmoduleID = FirstSubmoduleID; } void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) { IdentifierIDs[II] = ID; if (II->hasMacroDefinition()) DeserializedMacroNames.push_back(II); } void ASTWriter::TypeRead(TypeIdx Idx, QualType T) { // Always take the highest-numbered type index. This copes with an interesting // case for chained AST writing where we schedule writing the type and then, // later, deserialize the type from another AST. In this case, we want to // keep the higher-numbered entry so that we can properly write it out to // the AST file. TypeIdx &StoredIdx = TypeIdxs[T]; if (Idx.getIndex() >= StoredIdx.getIndex()) StoredIdx = Idx; } void ASTWriter::SelectorRead(SelectorID ID, Selector S) { SelectorIDs[S] = ID; } void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID, MacroDefinition *MD) { assert(MacroDefinitions.find(MD) == MacroDefinitions.end()); MacroDefinitions[MD] = ID; } void ASTWriter::MacroVisible(IdentifierInfo *II) { DeserializedMacroNames.push_back(II); } void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) { assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end()); SubmoduleIDs[Mod] = ID; } void ASTWriter::CompletedTagDefinition(const TagDecl *D) { assert(D->isCompleteDefinition()); assert(!WritingAST && "Already writing the AST!"); if (const CXXRecordDecl *RD = dyn_cast(D)) { // We are interested when a PCH decl is modified. if (RD->isFromASTFile()) { // A forward reference was mutated into a definition. Rewrite it. // FIXME: This happens during template instantiation, should we // have created a new definition decl instead ? RewriteDecl(RD); } } } void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) { assert(!WritingAST && "Already writing the AST!"); // TU and namespaces are handled elsewhere. if (isa(DC) || isa(DC)) return; if (!(!D->isFromASTFile() && cast(DC)->isFromASTFile())) return; // Not a source decl added to a DeclContext from PCH. AddUpdatedDeclContext(DC); } void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) { assert(!WritingAST && "Already writing the AST!"); assert(D->isImplicit()); if (!(!D->isFromASTFile() && RD->isFromASTFile())) return; // Not a source member added to a class from PCH. if (!isa(D)) return; // We are interested in lazily declared implicit methods. // A decl coming from PCH was modified. assert(RD->isCompleteDefinition()); UpdateRecord &Record = DeclUpdates[RD]; Record.push_back(UPD_CXX_ADDED_IMPLICIT_MEMBER); Record.push_back(reinterpret_cast(D)); } void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) { // The specializations set is kept in the canonical template. assert(!WritingAST && "Already writing the AST!"); TD = TD->getCanonicalDecl(); if (!(!D->isFromASTFile() && TD->isFromASTFile())) return; // Not a source specialization added to a template from PCH. UpdateRecord &Record = DeclUpdates[TD]; Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); Record.push_back(reinterpret_cast(D)); } void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D) { // The specializations set is kept in the canonical template. assert(!WritingAST && "Already writing the AST!"); TD = TD->getCanonicalDecl(); if (!(!D->isFromASTFile() && TD->isFromASTFile())) return; // Not a source specialization added to a template from PCH. UpdateRecord &Record = DeclUpdates[TD]; Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); Record.push_back(reinterpret_cast(D)); } void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; // Declaration not imported from PCH. // Implicit decl from a PCH was defined. // FIXME: Should implicit definition be a separate FunctionDecl? RewriteDecl(D); } void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; // Since the actual instantiation is delayed, this really means that we need // to update the instantiation location. UpdateRecord &Record = DeclUpdates[D]; Record.push_back(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER); AddSourceLocation( D->getMemberSpecializationInfo()->getPointOfInstantiation(), Record); } void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) { assert(!WritingAST && "Already writing the AST!"); if (!IFD->isFromASTFile()) return; // Declaration not imported from PCH. assert(IFD->getDefinition() && "Category on a class without a definition?"); ObjCClassesWithCategories.insert( const_cast(IFD->getDefinition())); } void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop, const ObjCPropertyDecl *OrigProp, const ObjCCategoryDecl *ClassExt) { const ObjCInterfaceDecl *D = ClassExt->getClassInterface(); if (!D) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; // Declaration not imported from PCH. RewriteDecl(D); } Index: vendor/clang/dist/test/CXX/class/class.mem/p2.cpp =================================================================== --- vendor/clang/dist/test/CXX/class/class.mem/p2.cpp (revision 235808) +++ vendor/clang/dist/test/CXX/class/class.mem/p2.cpp (revision 235809) @@ -1,58 +1,58 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s // C++11 [class.mem]p2: // A class is considered a completely-defined object type (or // complete type) at the closing } of the class-specifier. Within // the class member-specification, the class is regarded as complete // within function bodies, default arguments, // exception-specifications, and brace-or-equal-initializers for // non-static data members (including such things in nested classes). // Otherwise it is regarded as incomplete within its own class // member-specification. namespace test0 { struct A { // expected-note {{definition of 'test0::A' is not complete until the closing '}'}} A x; // expected-error {{field has incomplete type 'test0::A'}} }; } namespace test1 { template struct A { A x; // expected-error {{implicit instantiation of template 'test1::A' within its own definition}} }; } namespace test2 { template struct A; template <> struct A {}; template struct A { A x; }; } namespace test3 { struct A { struct B { void f() throw(A); void g() throw(B); }; void f() throw(A); void g() throw(B); }; template struct A2 { struct B { void f1() throw(A2); void f2() throw(A2); void g() throw(B); }; void f1() throw(A2); void f2() throw(A2); void g() throw(B); }; template struct A2; } Index: vendor/clang/dist/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp =================================================================== --- vendor/clang/dist/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp (revision 235808) +++ vendor/clang/dist/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp (revision 235809) @@ -1,100 +1,101 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify struct A { int &f(int*); float &f(int*) const noexcept; int *ptr; auto g1() noexcept(noexcept(f(ptr))) -> decltype(f(this->ptr)); auto g2() const noexcept(noexcept(f((*this).ptr))) -> decltype(f(ptr)); }; void testA(A &a) { int &ir = a.g1(); float &fr = a.g2(); static_assert(!noexcept(a.g1()), "exception-specification failure"); static_assert(noexcept(a.g2()), "exception-specification failure"); } struct B { char g(); template auto f(T t) -> decltype(t + g()) { return t + g(); } }; template auto B::f(int t) -> decltype(t + g()); template struct C { int &f(T*); float &f(T*) const noexcept; T* ptr; auto g1() noexcept(noexcept(f(ptr))) -> decltype(f((*this).ptr)); auto g2() const noexcept(noexcept(f(((this))->ptr))) -> decltype(f(ptr)); }; void test_C(C ci) { int *p = 0; int &ir = ci.g1(); float &fr = ci.g2(); static_assert(!noexcept(ci.g1()), "exception-specification failure"); static_assert(noexcept(ci.g2()), "exception-specification failure"); } namespace PR10036 { template void iter_swap(I x, I y) noexcept; template class A { T t_; public: void swap(A& a) noexcept(noexcept(iter_swap(&t_, &a.t_))); }; void test() { A i, j; i.swap(j); } } namespace Static { struct X1 { int m; static auto f() -> decltype(m); // expected-error{{'this' cannot be implicitly used in a static member function declaration}} static auto g() -> decltype(this->m); // expected-error{{'this' cannot be used in a static member function declaration}} static int h(); static int i() noexcept(noexcept(m + 2)); // expected-error{{'this' cannot be implicitly used in a static member function declaration}} }; auto X1::h() -> decltype(m) { return 0; } // expected-error{{'this' cannot be implicitly used in a static member function declaration}} template struct X2 { int m; T f(T*); static T f(int); auto g(T x) -> decltype(f(x)) { return 0; } }; void test_X2() { X2().g(0); } } namespace PR12564 { struct Base { - void bar(Base&) {} + void bar(Base&) {} // unexpected-note {{here}} }; struct Derived : Base { - void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} + // FIXME: This should be accepted. + void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} // unexpected-error {{cannot bind to a value of unrelated type}} }; } Index: vendor/clang/dist/test/CXX/special/class.copy/implicit-move.cpp =================================================================== --- vendor/clang/dist/test/CXX/special/class.copy/implicit-move.cpp (revision 235808) +++ vendor/clang/dist/test/CXX/special/class.copy/implicit-move.cpp (revision 235809) @@ -1,236 +1,236 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s // Tests for implicit (non-)declaration of move constructor and // assignment: p9, p11, p20, p23. // This class, used as a member, allows to distinguish move from copy because // move operations are no-throw, copy operations aren't. struct ThrowingCopy { ThrowingCopy() noexcept; ThrowingCopy(ThrowingCopy &&) noexcept; ThrowingCopy(const ThrowingCopy &) noexcept(false); ThrowingCopy & operator =(ThrowingCopy &&) noexcept; ThrowingCopy & operator =(const ThrowingCopy &) noexcept(false); }; struct HasCopyConstructor { ThrowingCopy tc; HasCopyConstructor() noexcept; HasCopyConstructor(const HasCopyConstructor &) noexcept(false); }; struct HasCopyAssignment { ThrowingCopy tc; HasCopyAssignment() noexcept; HasCopyAssignment & operator =(const HasCopyAssignment &) noexcept(false); }; struct HasMoveConstructor { ThrowingCopy tc; HasMoveConstructor() noexcept; HasMoveConstructor(HasMoveConstructor &&) noexcept; // expected-note {{copy assignment operator is implicitly deleted because 'HasMoveConstructor' has a user-declared move constructor}} }; struct HasMoveAssignment { // expected-note {{implicit copy constructor}} ThrowingCopy tc; HasMoveAssignment() noexcept; HasMoveAssignment & operator =(HasMoveAssignment &&) noexcept; }; struct HasDestructor { ThrowingCopy tc; HasDestructor() noexcept; ~HasDestructor() noexcept; }; void test_basic_exclusion() { static_assert(!noexcept(HasCopyConstructor((HasCopyConstructor()))), ""); HasCopyConstructor hcc; static_assert(!noexcept(hcc = HasCopyConstructor()), ""); static_assert(!noexcept(HasCopyAssignment((HasCopyAssignment()))), ""); HasCopyAssignment hca; static_assert(!noexcept(hca = HasCopyAssignment()), ""); static_assert(noexcept(HasMoveConstructor((HasMoveConstructor()))), ""); HasMoveConstructor hmc; hmc = HasMoveConstructor(); // expected-error {{selected implicitly-deleted copy assignment}} (HasMoveAssignment(HasMoveAssignment())); // expected-error {{uses deleted function}} HasMoveAssignment hma; static_assert(noexcept(hma = HasMoveAssignment()), ""); static_assert(!noexcept(HasDestructor((HasDestructor()))), ""); HasDestructor hd; static_assert(!noexcept(hd = HasDestructor()), ""); } struct PrivateMove { PrivateMove() noexcept; PrivateMove(const PrivateMove &) noexcept(false); PrivateMove & operator =(const PrivateMove &) noexcept(false); private: PrivateMove(PrivateMove &&) noexcept; PrivateMove & operator =(PrivateMove &&) noexcept; }; struct InheritsPrivateMove : PrivateMove {}; struct ContainsPrivateMove { PrivateMove pm; }; struct PrivateDestructor { PrivateDestructor() noexcept; PrivateDestructor(const PrivateDestructor &) noexcept(false); PrivateDestructor(PrivateDestructor &&) noexcept; private: ~PrivateDestructor() noexcept; }; struct InheritsPrivateDestructor : PrivateDestructor {}; // expected-note{{base class 'PrivateDestructor' has an inaccessible destructor}} struct ContainsPrivateDestructor { PrivateDestructor pd; // expected-note{{field 'pd' has an inaccessible destructor}} }; struct NonTrivialCopyOnly { NonTrivialCopyOnly() noexcept; NonTrivialCopyOnly(const NonTrivialCopyOnly &) noexcept(false); NonTrivialCopyOnly & operator =(const NonTrivialCopyOnly &) noexcept(false); }; struct InheritsNonTrivialCopyOnly : NonTrivialCopyOnly {}; struct ContainsNonTrivialCopyOnly { NonTrivialCopyOnly ntco; }; struct ContainsConst { const int i; ContainsConst() noexcept; ContainsConst & operator =(ContainsConst &); // expected-note {{not viable}} }; struct ContainsRef { int &i; ContainsRef() noexcept; ContainsRef & operator =(ContainsRef &); // expected-note {{not viable}} }; struct Base { Base & operator =(Base &); }; struct DirectVirtualBase : virtual Base {}; // expected-note {{copy assignment operator) not viable}} struct IndirectVirtualBase : DirectVirtualBase {}; // expected-note {{copy assignment operator) not viable}} void test_deletion_exclusion() { // FIXME: How to test the union thing? static_assert(!noexcept(InheritsPrivateMove(InheritsPrivateMove())), ""); static_assert(!noexcept(ContainsPrivateMove(ContainsPrivateMove())), ""); InheritsPrivateMove ipm; static_assert(!noexcept(ipm = InheritsPrivateMove()), ""); ContainsPrivateMove cpm; static_assert(!noexcept(cpm = ContainsPrivateMove()), ""); (InheritsPrivateDestructor(InheritsPrivateDestructor())); // expected-error {{call to implicitly-deleted default constructor}} (ContainsPrivateDestructor(ContainsPrivateDestructor())); // expected-error {{call to implicitly-deleted default constructor}} static_assert(!noexcept(InheritsNonTrivialCopyOnly(InheritsNonTrivialCopyOnly())), ""); static_assert(!noexcept(ContainsNonTrivialCopyOnly(ContainsNonTrivialCopyOnly())), ""); InheritsNonTrivialCopyOnly intco; static_assert(!noexcept(intco = InheritsNonTrivialCopyOnly()), ""); ContainsNonTrivialCopyOnly cntco; static_assert(!noexcept(cntco = ContainsNonTrivialCopyOnly()), ""); ContainsConst cc; cc = ContainsConst(); // expected-error {{no viable}} ContainsRef cr; cr = ContainsRef(); // expected-error {{no viable}} DirectVirtualBase dvb; dvb = DirectVirtualBase(); // expected-error {{no viable}} IndirectVirtualBase ivb; ivb = IndirectVirtualBase(); // expected-error {{no viable}} } struct ContainsRValueRef { int&& ri; ContainsRValueRef() noexcept; }; void test_contains_rref() { (ContainsRValueRef(ContainsRValueRef())); } namespace DR1402 { struct NonTrivialCopyCtor { NonTrivialCopyCtor(const NonTrivialCopyCtor &); }; struct NonTrivialCopyAssign { NonTrivialCopyAssign &operator=(const NonTrivialCopyAssign &); }; struct NonTrivialCopyCtorVBase : virtual NonTrivialCopyCtor { NonTrivialCopyCtorVBase(NonTrivialCopyCtorVBase &&); NonTrivialCopyCtorVBase &operator=(NonTrivialCopyCtorVBase &&) = default; }; struct NonTrivialCopyAssignVBase : virtual NonTrivialCopyAssign { NonTrivialCopyAssignVBase(NonTrivialCopyAssignVBase &&); NonTrivialCopyAssignVBase &operator=(NonTrivialCopyAssignVBase &&) = default; }; struct NonTrivialMoveAssign { NonTrivialMoveAssign(NonTrivialMoveAssign&&); NonTrivialMoveAssign &operator=(NonTrivialMoveAssign &&); }; struct NonTrivialMoveAssignVBase : virtual NonTrivialMoveAssign { NonTrivialMoveAssignVBase(NonTrivialMoveAssignVBase &&); NonTrivialMoveAssignVBase &operator=(NonTrivialMoveAssignVBase &&) = default; }; // A non-movable, non-trivially-copyable class type as a subobject inhibits // the declaration of a move operation. struct NoMove1 { NonTrivialCopyCtor ntcc; }; // expected-note 2{{'const DR1402::NoMove1 &'}} struct NoMove2 { NonTrivialCopyAssign ntcc; }; // expected-note 2{{'const DR1402::NoMove2 &'}} struct NoMove3 : NonTrivialCopyCtor {}; // expected-note 2{{'const DR1402::NoMove3 &'}} struct NoMove4 : NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove4 &'}} struct NoMove5 : virtual NonTrivialCopyCtor {}; // expected-note 2{{'const DR1402::NoMove5 &'}} struct NoMove6 : virtual NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove6 &'}} - struct NoMove7 : NonTrivialCopyCtorVBase {}; // expected-note 2{{'DR1402::NoMove7 &'}} - struct NoMove8 : NonTrivialCopyAssignVBase {}; // expected-note 2{{'DR1402::NoMove8 &'}} + struct NoMove7 : NonTrivialCopyCtorVBase {}; // expected-note 2{{'const DR1402::NoMove7 &'}} + struct NoMove8 : NonTrivialCopyAssignVBase {}; // expected-note 2{{'const DR1402::NoMove8 &'}} // A non-trivially-move-assignable virtual base class inhibits the declaration // of a move assignment (which might move-assign the base class multiple // times). struct NoMove9 : NonTrivialMoveAssign {}; - struct NoMove10 : virtual NonTrivialMoveAssign {}; // expected-note {{'DR1402::NoMove10 &'}} - struct NoMove11 : NonTrivialMoveAssignVBase {}; // expected-note {{'DR1402::NoMove11 &'}} + struct NoMove10 : virtual NonTrivialMoveAssign {}; // expected-note {{'const DR1402::NoMove10 &'}} + struct NoMove11 : NonTrivialMoveAssignVBase {}; // expected-note {{'const DR1402::NoMove11 &'}} struct Test { friend NoMove1::NoMove1(NoMove1 &&); // expected-error {{no matching function}} friend NoMove2::NoMove2(NoMove2 &&); // expected-error {{no matching function}} friend NoMove3::NoMove3(NoMove3 &&); // expected-error {{no matching function}} friend NoMove4::NoMove4(NoMove4 &&); // expected-error {{no matching function}} friend NoMove5::NoMove5(NoMove5 &&); // expected-error {{no matching function}} friend NoMove6::NoMove6(NoMove6 &&); // expected-error {{no matching function}} friend NoMove7::NoMove7(NoMove7 &&); // expected-error {{no matching function}} friend NoMove8::NoMove8(NoMove8 &&); // expected-error {{no matching function}} friend NoMove9::NoMove9(NoMove9 &&); friend NoMove10::NoMove10(NoMove10 &&); friend NoMove11::NoMove11(NoMove11 &&); friend NoMove1 &NoMove1::operator=(NoMove1 &&); // expected-error {{no matching function}} friend NoMove2 &NoMove2::operator=(NoMove2 &&); // expected-error {{no matching function}} friend NoMove3 &NoMove3::operator=(NoMove3 &&); // expected-error {{no matching function}} friend NoMove4 &NoMove4::operator=(NoMove4 &&); // expected-error {{no matching function}} friend NoMove5 &NoMove5::operator=(NoMove5 &&); // expected-error {{no matching function}} friend NoMove6 &NoMove6::operator=(NoMove6 &&); // expected-error {{no matching function}} friend NoMove7 &NoMove7::operator=(NoMove7 &&); // expected-error {{no matching function}} friend NoMove8 &NoMove8::operator=(NoMove8 &&); // expected-error {{no matching function}} friend NoMove9 &NoMove9::operator=(NoMove9 &&); friend NoMove10 &NoMove10::operator=(NoMove10 &&); // expected-error {{no matching function}} friend NoMove11 &NoMove11::operator=(NoMove11 &&); // expected-error {{no matching function}} }; } Index: vendor/clang/dist/test/CXX/special/class.copy/p8-cxx11.cpp =================================================================== --- vendor/clang/dist/test/CXX/special/class.copy/p8-cxx11.cpp (nonexistent) +++ vendor/clang/dist/test/CXX/special/class.copy/p8-cxx11.cpp (revision 235809) @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -std=c++11 %s -verify + +// C++98 [class.copy]p5 / C++11 [class.copy]p8. + +// The implicitly-declared copy constructor for a class X will have the form +// X::X(const X&) +// if [every direct subobject] has a copy constructor whose first parameter is +// of type 'const volatile[opt] T &'. Otherwise, it will have the form +// X::X(X&) + +struct ConstCopy { + ConstCopy(const ConstCopy &); +}; + +struct NonConstCopy { + NonConstCopy(NonConstCopy &); +}; + +struct DeletedConstCopy { + DeletedConstCopy(const DeletedConstCopy &) = delete; +}; + +struct DeletedNonConstCopy { + DeletedNonConstCopy(DeletedNonConstCopy &) = delete; +}; + +struct ImplicitlyDeletedConstCopy { + ImplicitlyDeletedConstCopy(ImplicitlyDeletedConstCopy &&); +}; + + +struct A : ConstCopy {}; +struct B : NonConstCopy { ConstCopy a; }; +struct C : ConstCopy { NonConstCopy a; }; +struct D : DeletedConstCopy {}; +struct E : DeletedNonConstCopy {}; +struct F { ImplicitlyDeletedConstCopy a; }; +struct G : virtual B {}; + +struct Test { + friend A::A(const A &); + friend B::B(B &); + friend C::C(C &); + friend D::D(const D &); + friend E::E(E &); + friend F::F(const F &); + friend G::G(G &); +}; Index: vendor/clang/dist/test/CodeGenCXX/x86-64-abi-sret-vs-2word-struct-param.cpp =================================================================== --- vendor/clang/dist/test/CodeGenCXX/x86-64-abi-sret-vs-2word-struct-param.cpp (revision 235808) +++ vendor/clang/dist/test/CodeGenCXX/x86-64-abi-sret-vs-2word-struct-param.cpp (nonexistent) @@ -1,29 +0,0 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s -// XTARGET: x86 -// PR4242 -// (PR 4242 bug is on 64-bit only, test passes on x86-32 as well) - -struct S { - void* data[3]; -}; - -struct T { - void* data[2]; -}; - -// CHECK: %struct.T* byval -extern "C" S fail(int, int, int, int, T t, void* p) { - S s; - s.data[0] = t.data[0]; - s.data[1] = t.data[1]; - s.data[2] = p; - return s; -} - -// CHECK: %struct.T* byval -extern "C" S* succeed(S* sret, int, int, int, int, T t, void* p) { - sret->data[0] = t.data[0]; - sret->data[1] = t.data[1]; - sret->data[2] = p; - return sret; -} Index: vendor/clang/dist/test/CodeGenCXX/x86_64-arguments.cpp =================================================================== --- vendor/clang/dist/test/CodeGenCXX/x86_64-arguments.cpp (revision 235808) +++ vendor/clang/dist/test/CodeGenCXX/x86_64-arguments.cpp (revision 235809) @@ -1,151 +1,183 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s // Basic base class test. struct f0_s0 { unsigned a; }; struct f0_s1 : public f0_s0 { void *b; }; // CHECK: define void @_Z2f05f0_s1(i32 %a0.coerce0, i8* %a0.coerce1) void f0(f0_s1 a0) { } // Check with two eight-bytes in base class. struct f1_s0 { unsigned a; unsigned b; float c; }; struct f1_s1 : public f1_s0 { float d;}; // CHECK: define void @_Z2f15f1_s1(i64 %a0.coerce0, <2 x float> %a0.coerce1) void f1(f1_s1 a0) { } // Check with two eight-bytes in base class and merge. struct f2_s0 { unsigned a; unsigned b; float c; }; struct f2_s1 : public f2_s0 { char d;}; // CHECK: define void @_Z2f25f2_s1(i64 %a0.coerce0, i64 %a0.coerce1) void f2(f2_s1 a0) { } // PR5831 // CHECK: define void @_Z2f34s3_1(i64 %x.coerce) struct s3_0 {}; struct s3_1 { struct s3_0 a; long b; }; void f3(struct s3_1 x) {} // CHECK: define i64 @_Z4f4_0M2s4i(i64 %a) // CHECK: define {{.*}} @_Z4f4_1M2s4FivE(i64 %a.coerce0, i64 %a.coerce1) struct s4 {}; typedef int s4::* s4_mdp; typedef int (s4::*s4_mfp)(); s4_mdp f4_0(s4_mdp a) { return a; } s4_mfp f4_1(s4_mfp a) { return a; } namespace PR7523 { struct StringRef { char *a; }; void AddKeyword(StringRef, int x); void foo() { // CHECK: define void @_ZN6PR75233fooEv() // CHECK: call void @_ZN6PR752310AddKeywordENS_9StringRefEi(i8* {{.*}}, i32 4) AddKeyword(StringRef(), 4); } } namespace PR7742 { // Also rdar://8250764 struct s2 { float a[2]; }; struct c2 : public s2 {}; // CHECK: define <2 x float> @_ZN6PR77423fooEPNS_2c2E(%"struct.PR7742::c2"* %P) c2 foo(c2 *P) { + return c2(); } } namespace PR5179 { struct B {}; struct B1 : B { int* pa; }; struct B2 : B { B1 b1; }; // CHECK: define i8* @_ZN6PR51793barENS_2B2E(i32* %b2.coerce) const void *bar(B2 b2) { return b2.b1.pa; } } namespace test5 { struct Xbase { }; struct Empty { }; struct Y; struct X : public Xbase { Empty empty; Y f(); }; struct Y : public X { Empty empty; }; X getX(); int takeY(const Y&, int y); void g() { // rdar://8340348 - The temporary for the X object needs to have a defined // address when passed into X::f as 'this'. takeY(getX().f(), 42); } // CHECK: void @_ZN5test51gEv() // CHECK: alloca %"struct.test5::Y" // CHECK: alloca %"struct.test5::X" // CHECK: alloca %"struct.test5::Y" } // rdar://8360877 namespace test6 { struct outer { int x; struct epsilon_matcher {} e; int f; }; int test(outer x) { return x.x + x.f; } // CHECK: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1) } namespace test7 { struct StringRef {char* ptr; long len; }; class A { public: ~A(); }; A x(A, A, long, long, StringRef) { return A(); } // Check that the StringRef is passed byval instead of expanded // (which would split it between registers and memory). // rdar://problem/9686430 // CHECK: define void @_ZN5test71xENS_1AES0_llNS_9StringRefE({{.*}} byval align 8) // And a couple extra related tests: A y(A, long double, long, long, StringRef) { return A(); } // CHECK: define void @_ZN5test71yENS_1AEellNS_9StringRefE({{.*}} i8* struct StringDouble {char * ptr; double d;}; A z(A, A, A, A, A, StringDouble) { return A(); } A zz(A, A, A, A, StringDouble) { return A(); } // CHECK: define void @_ZN5test71zENS_1AES0_S0_S0_S0_NS_12StringDoubleE({{.*}} byval align 8) // CHECK: define void @_ZN5test72zzENS_1AES0_S0_S0_NS_12StringDoubleE({{.*}} i8* } namespace test8 { // CHECK: declare void @_ZN5test83fooENS_1BE(%"class.test8::B"* byval align 8) class A { char big[17]; }; class B : public A {}; void foo(B b); void bar() { B b; foo(b); + } +} + +// PR4242 +namespace test9 { + // Large enough to be passed indirectly. + struct S { void *data[3]; }; + + struct T { void *data[2]; }; + + // CHECK: define void @_ZN5test93fooEPNS_1SEPNS_1TE([[S:%.*]]*, [[T:%.*]]*) + void foo(S*, T*) {} + + // CHECK: define void @_ZN5test91aEiiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32, i32, i32, i32, [[T]]* byval align 8, i8*) + S a(int, int, int, int, T, void*) { + return S(); + } + + // CHECK: define [[S]]* @_ZN5test91bEPNS_1SEiiiiNS_1TEPv([[S]]* {{%.*}}, i32, i32, i32, i32, [[T:%.*]]* byval align 8, i8*) + S* b(S* sret, int, int, int, int, T, void*) { + return sret; + } + + // CHECK: define void @_ZN5test91cEiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32, i32, i32, i8* {{%.*}}, i8* {{%.*}}, i8*) + S c(int, int, int, T, void*) { + return S(); + } + + // CHECK: define [[S]]* @_ZN5test91dEPNS_1SEiiiNS_1TEPv([[S]]* {{%.*}}, i32, i32, i32, i8* {{%.*}}, i8* {{%.*}}, i8*) + S* d(S* sret, int, int, int, T, void*) { + return sret; } } Index: vendor/clang/dist/test/PCH/cxx11-exception-spec.cpp =================================================================== --- vendor/clang/dist/test/PCH/cxx11-exception-spec.cpp (nonexistent) +++ vendor/clang/dist/test/PCH/cxx11-exception-spec.cpp (revision 235809) @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t +// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s + +#ifndef HEADER_INCLUDED + +#define HEADER_INCLUDED + +template int f() noexcept(b) {} +decltype(f()) a; +decltype(f()) b; + +#else + +static_assert(!noexcept(f()), ""); +static_assert(noexcept(f()), ""); + +#endif Index: vendor/clang/dist/test/Parser/recursion-limits.cpp =================================================================== --- vendor/clang/dist/test/Parser/recursion-limits.cpp (nonexistent) +++ vendor/clang/dist/test/Parser/recursion-limits.cpp (revision 235809) @@ -0,0 +1,259 @@ +// RUN: %clang_cc1 -fsyntax-only %s -verify +class outer { + class inner1 { inner1(); }; + class inner2 { inner2(); }; + class inner3 { inner3(); }; + class inner4 { inner4(); }; + class inner5 { inner5(); }; + class inner6 { inner6(); }; + class inner7 { inner7(); }; + class inner8 { inner8(); }; + class inner9 { inner9(); }; + class inner10 { inner10(); }; + class inner11 { inner11(); }; + class inner12 { inner12(); }; + class inner13 { inner13(); }; + class inner14 { inner14(); }; + class inner15 { inner15(); }; + class inner16 { inner16(); }; + class inner17 { inner17(); }; + class inner18 { inner18(); }; + class inner19 { inner19(); }; + class inner20 { inner20(); }; + class inner21 { inner21(); }; + class inner22 { inner22(); }; + class inner23 { inner23(); }; + class inner24 { inner24(); }; + class inner25 { inner25(); }; + class inner26 { inner26(); }; + class inner27 { inner27(); }; + class inner28 { inner28(); }; + class inner29 { inner29(); }; + class inner30 { inner30(); }; + class inner31 { inner31(); }; + class inner32 { inner32(); }; + class inner33 { inner33(); }; + class inner34 { inner34(); }; + class inner35 { inner35(); }; + class inner36 { inner36(); }; + class inner37 { inner37(); }; + class inner38 { inner38(); }; + class inner39 { inner39(); }; + class inner40 { inner40(); }; + class inner41 { inner41(); }; + class inner42 { inner42(); }; + class inner43 { inner43(); }; + class inner44 { inner44(); }; + class inner45 { inner45(); }; + class inner46 { inner46(); }; + class inner47 { inner47(); }; + class inner48 { inner48(); }; + class inner49 { inner49(); }; + class inner50 { inner50(); }; + class inner51 { inner51(); }; + class inner52 { inner52(); }; + class inner53 { inner53(); }; + class inner54 { inner54(); }; + class inner55 { inner55(); }; + class inner56 { inner56(); }; + class inner57 { inner57(); }; + class inner58 { inner58(); }; + class inner59 { inner59(); }; + class inner60 { inner60(); }; + class inner61 { inner61(); }; + class inner62 { inner62(); }; + class inner63 { inner63(); }; + class inner64 { inner64(); }; + class inner65 { inner65(); }; + class inner66 { inner66(); }; + class inner67 { inner67(); }; + class inner68 { inner68(); }; + class inner69 { inner69(); }; + class inner70 { inner70(); }; + class inner71 { inner71(); }; + class inner72 { inner72(); }; + class inner73 { inner73(); }; + class inner74 { inner74(); }; + class inner75 { inner75(); }; + class inner76 { inner76(); }; + class inner77 { inner77(); }; + class inner78 { inner78(); }; + class inner79 { inner79(); }; + class inner80 { inner80(); }; + class inner81 { inner81(); }; + class inner82 { inner82(); }; + class inner83 { inner83(); }; + class inner84 { inner84(); }; + class inner85 { inner85(); }; + class inner86 { inner86(); }; + class inner87 { inner87(); }; + class inner88 { inner88(); }; + class inner89 { inner89(); }; + class inner90 { inner90(); }; + class inner91 { inner91(); }; + class inner92 { inner92(); }; + class inner93 { inner93(); }; + class inner94 { inner94(); }; + class inner95 { inner95(); }; + class inner96 { inner96(); }; + class inner97 { inner97(); }; + class inner98 { inner98(); }; + class inner99 { inner99(); }; + class inner100 { inner100(); }; + class inner101 { inner101(); }; + class inner102 { inner102(); }; + class inner103 { inner103(); }; + class inner104 { inner104(); }; + class inner105 { inner105(); }; + class inner106 { inner106(); }; + class inner107 { inner107(); }; + class inner108 { inner108(); }; + class inner109 { inner109(); }; + class inner110 { inner110(); }; + class inner111 { inner111(); }; + class inner112 { inner112(); }; + class inner113 { inner113(); }; + class inner114 { inner114(); }; + class inner115 { inner115(); }; + class inner116 { inner116(); }; + class inner117 { inner117(); }; + class inner118 { inner118(); }; + class inner119 { inner119(); }; + class inner120 { inner120(); }; + class inner121 { inner121(); }; + class inner122 { inner122(); }; + class inner123 { inner123(); }; + class inner124 { inner124(); }; + class inner125 { inner125(); }; + class inner126 { inner126(); }; + class inner127 { inner127(); }; + class inner128 { inner128(); }; + class inner129 { inner129(); }; + class inner130 { inner130(); }; + class inner131 { inner131(); }; + class inner132 { inner132(); }; + class inner133 { inner133(); }; + class inner134 { inner134(); }; + class inner135 { inner135(); }; + class inner136 { inner136(); }; + class inner137 { inner137(); }; + class inner138 { inner138(); }; + class inner139 { inner139(); }; + class inner140 { inner140(); }; + class inner141 { inner141(); }; + class inner142 { inner142(); }; + class inner143 { inner143(); }; + class inner144 { inner144(); }; + class inner145 { inner145(); }; + class inner146 { inner146(); }; + class inner147 { inner147(); }; + class inner148 { inner148(); }; + class inner149 { inner149(); }; + class inner150 { inner150(); }; + class inner151 { inner151(); }; + class inner152 { inner152(); }; + class inner153 { inner153(); }; + class inner154 { inner154(); }; + class inner155 { inner155(); }; + class inner156 { inner156(); }; + class inner157 { inner157(); }; + class inner158 { inner158(); }; + class inner159 { inner159(); }; + class inner160 { inner160(); }; + class inner161 { inner161(); }; + class inner162 { inner162(); }; + class inner163 { inner163(); }; + class inner164 { inner164(); }; + class inner165 { inner165(); }; + class inner166 { inner166(); }; + class inner167 { inner167(); }; + class inner168 { inner168(); }; + class inner169 { inner169(); }; + class inner170 { inner170(); }; + class inner171 { inner171(); }; + class inner172 { inner172(); }; + class inner173 { inner173(); }; + class inner174 { inner174(); }; + class inner175 { inner175(); }; + class inner176 { inner176(); }; + class inner177 { inner177(); }; + class inner178 { inner178(); }; + class inner179 { inner179(); }; + class inner180 { inner180(); }; + class inner181 { inner181(); }; + class inner182 { inner182(); }; + class inner183 { inner183(); }; + class inner184 { inner184(); }; + class inner185 { inner185(); }; + class inner186 { inner186(); }; + class inner187 { inner187(); }; + class inner188 { inner188(); }; + class inner189 { inner189(); }; + class inner190 { inner190(); }; + class inner191 { inner191(); }; + class inner192 { inner192(); }; + class inner193 { inner193(); }; + class inner194 { inner194(); }; + class inner195 { inner195(); }; + class inner196 { inner196(); }; + class inner197 { inner197(); }; + class inner198 { inner198(); }; + class inner199 { inner199(); }; + class inner200 { inner200(); }; + class inner201 { inner201(); }; + class inner202 { inner202(); }; + class inner203 { inner203(); }; + class inner204 { inner204(); }; + class inner205 { inner205(); }; + class inner206 { inner206(); }; + class inner207 { inner207(); }; + class inner208 { inner208(); }; + class inner209 { inner209(); }; + class inner210 { inner210(); }; + class inner211 { inner211(); }; + class inner212 { inner212(); }; + class inner213 { inner213(); }; + class inner214 { inner214(); }; + class inner215 { inner215(); }; + class inner216 { inner216(); }; + class inner217 { inner217(); }; + class inner218 { inner218(); }; + class inner219 { inner219(); }; + class inner220 { inner220(); }; + class inner221 { inner221(); }; + class inner222 { inner222(); }; + class inner223 { inner223(); }; + class inner224 { inner224(); }; + class inner225 { inner225(); }; + class inner226 { inner226(); }; + class inner227 { inner227(); }; + class inner228 { inner228(); }; + class inner229 { inner229(); }; + class inner230 { inner230(); }; + class inner231 { inner231(); }; + class inner232 { inner232(); }; + class inner233 { inner233(); }; + class inner234 { inner234(); }; + class inner235 { inner235(); }; + class inner236 { inner236(); }; + class inner237 { inner237(); }; + class inner238 { inner238(); }; + class inner239 { inner239(); }; + class inner240 { inner240(); }; + class inner241 { inner241(); }; + class inner242 { inner242(); }; + class inner243 { inner243(); }; + class inner244 { inner244(); }; + class inner245 { inner245(); }; + class inner246 { inner246(); }; + class inner247 { inner247(); }; + class inner248 { inner248(); }; + class inner249 { inner249(); }; + class inner250 { inner250(); }; + class inner251 { inner251(); }; + class inner252 { inner252(); }; + class inner253 { inner253(); }; + class inner254 { inner254(); }; + class inner255 { inner255(); }; + class inner256 { inner256(); }; +}; Index: vendor/clang/dist/test/Rewriter/rewrite-modern-extern-c-func-decl.mm =================================================================== --- vendor/clang/dist/test/Rewriter/rewrite-modern-extern-c-func-decl.mm (revision 235808) +++ vendor/clang/dist/test/Rewriter/rewrite-modern-extern-c-func-decl.mm (revision 235809) @@ -1,48 +1,45 @@ -// RUN: %clang_cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks -o %t-rw.cpp %s -// RUN: %clang_cc1 -fsyntax-only -Werror -Wno-address-of-temporary -Wno-attributes -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -fms-extensions -U__declspec -rewrite-objc -x objective-c++ -fblocks -o %t-rw.cpp %s +// RUN: %clang_cc1 -fsyntax-only -Werror -Wno-address-of-temporary -Wno-attributes -D"Class=void*" -D"id=void*" -D"SEL=void*" -U__declspec -D"__declspec(X)=" %t-rw.cpp // rdar://11131490 - -// XFAIL: mingw -// FIXME: __declspec(X) is predefined on mingw. extern "C" __declspec(dllexport) void BreakTheRewriter(void) { __block int aBlockVariable = 0; void (^aBlock)(void) = ^ { aBlockVariable = 42; }; aBlockVariable++; void (^bBlocks)(void) = ^ { aBlockVariable = 43; }; void (^c)(void) = ^ { aBlockVariable = 44; }; } __declspec(dllexport) extern "C" void AnotherBreakTheRewriter(int *p1, double d) { __block int bBlockVariable = 0; void (^aBlock)(void) = ^ { bBlockVariable = 42; }; bBlockVariable++; void (^bBlocks)(void) = ^ { bBlockVariable = 43; }; void (^c)(void) = ^ { bBlockVariable = 44; }; } int __declspec (dllexport) main (int argc, char *argv[]) { __block int bBlockVariable = 0; void (^aBlock)(void) = ^ { bBlockVariable = 42; }; } Index: vendor/clang/dist/test/SemaCXX/cxx0x-initializer-references.cpp =================================================================== --- vendor/clang/dist/test/SemaCXX/cxx0x-initializer-references.cpp (revision 235808) +++ vendor/clang/dist/test/SemaCXX/cxx0x-initializer-references.cpp (revision 235809) @@ -1,87 +1,92 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s struct one { char c; }; struct two { char c[2]; }; namespace reference { struct A { int i1, i2; }; void single_init() { const int &cri1a = {1}; const int &cri1b{1}; int i = 1; int &ri1a = {i}; int &ri1b{i}; int &ri2 = {1}; // expected-error {{cannot bind to an initializer list temporary}} A a{1, 2}; A &ra1a = {a}; A &ra1b{a}; } void reference_to_aggregate() { const A &ra1{1, 2}; A &ra2{1, 2}; // expected-error {{cannot bind to an initializer list temporary}} const int (&arrayRef)[] = {1, 2, 3}; static_assert(sizeof(arrayRef) == 3 * sizeof(int), "bad array size"); } struct B { int i1; }; void call() { void f(const int&); f({1}); void g(int&); // expected-note {{passing argument}} g({1}); // expected-error {{cannot bind to an initializer list temporary}} int i = 0; g({i}); void h(const B&); h({1}); void a(B&); // expected-note {{passing argument}} a({1}); // expected-error {{cannot bind to an initializer list temporary}} B b{1}; a({b}); } void overloading() { one f(const int&); two f(const B&); // First is identity conversion, second is user-defined conversion. static_assert(sizeof(f({1})) == sizeof(one), "bad overload resolution"); one g(int&); two g(const B&); static_assert(sizeof(g({1})) == sizeof(two), "bad overload resolution"); one h(const int&); two h(const A&); static_assert(sizeof(h({1, 2})) == sizeof(two), "bad overload resolution"); } void edge_cases() { // FIXME: very poor error message int const &b({0}); // expected-error {{could not bind}} } } namespace PR12182 { void f(int const(&)[3]); void g() { f({1, 2}); } } + +namespace PR12660 { + const int &i { 1 }; + struct S { S(int); } const &s { 2 }; +} Index: vendor/clang/dist/test/SemaCXX/dependent-noexcept-unevaluated.cpp =================================================================== --- vendor/clang/dist/test/SemaCXX/dependent-noexcept-unevaluated.cpp (revision 235808) +++ vendor/clang/dist/test/SemaCXX/dependent-noexcept-unevaluated.cpp (revision 235809) @@ -1,41 +1,40 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s template T&& declval() noexcept; template struct some_trait { static const bool value = false; }; template void swap(T& x, T& y) noexcept(some_trait::value) { T tmp(static_cast(x)); x = static_cast(y); y = static_cast(tmp); } template struct array { T data[N]; - void swap(array& a) noexcept(noexcept(::swap(declval(), declval()))); + void swap(array& a) noexcept(noexcept(swap(declval(), declval()))); }; struct DefaultOnly { DefaultOnly() = default; DefaultOnly(const DefaultOnly&) = delete; DefaultOnly& operator=(const DefaultOnly&) = delete; ~DefaultOnly() = default; }; int main() { array a, b; } - Index: vendor/clang/dist/test/SemaCXX/implicit-exception-spec.cpp =================================================================== --- vendor/clang/dist/test/SemaCXX/implicit-exception-spec.cpp (revision 235808) +++ vendor/clang/dist/test/SemaCXX/implicit-exception-spec.cpp (revision 235809) @@ -1,56 +1,89 @@ // RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall %s template struct ExceptionIf { static int f(); }; template<> struct ExceptionIf { typedef int f; }; // The exception specification of a defaulted default constructor depends on // the contents of in-class member initializers. However, the in-class member // initializers can depend on the exception specification of the constructor, // since the class is considered complete within them. We reject any such cases. namespace InClassInitializers { // Noexcept::Noexcept() is implicitly declared as noexcept(false), because it // directly invokes ThrowSomething(). However... // // If noexcept(Noexcept()) is false, then Noexcept() is a constant expression, // so noexcept(Noexcept()) is true. But if noexcept(Noexcept()) is true, then // Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept()) // is false. bool ThrowSomething() noexcept(false); struct ConstExpr { bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{exception specification is not available until end of class definition}} }; // We can use it now. bool w = noexcept(ConstExpr()); // Much more obviously broken: we can't parse the initializer without already // knowing whether it produces a noexcept expression. struct TemplateArg { int n = ExceptionIf::f(); // expected-error {{exception specification is not available until end of class definition}} }; bool x = noexcept(TemplateArg()); // And within a nested class. struct Nested { struct Inner { int n = ExceptionIf::f(); // expected-error {{exception specification is not available until end of class definition}} } inner; }; bool y = noexcept(Nested()); bool z = noexcept(Nested::Inner()); } namespace ExceptionSpecification { - struct Nested { + // A type is permitted to be used in a dynamic exception specification when it + // is still being defined, but isn't complete within such an exception + // specification. + struct Nested { // expected-note {{not complete}} struct T { - T() noexcept(!noexcept(Nested())); // expected-error{{exception specification is not available until end of class definition}} + T() noexcept(!noexcept(Nested())); // expected-error{{incomplete type}} } t; }; } namespace DefaultArgument { struct Default { struct T { T(int = ExceptionIf struct X : T { }; // expected-error 2{{private destructor}} struct Z; // expected-note{{forward declaration}} @interface A { X x; // expected-note{{implicit default destructor}} Y y; // expected-error{{private destructor}} } @end @implementation A // expected-note{{implicit default constructor}} @end @interface B { Z z; // expected-error{{incomplete type}} } @end @implementation B @end + +// +template struct Incomplete; // expected-note{{declared here}} + +@interface C { + Incomplete a[4][4][4]; // expected-error{{implicit instantiation of undefined template 'Incomplete'}} +} +@end