diff options
Diffstat (limited to 'include/clang/AST')
56 files changed, 7821 insertions, 3365 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index a9ab687a8de9..13870116c7fd 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_AST_ASTCONTEXT_H #define LLVM_CLANG_AST_ASTCONTEXT_H +#include "clang/AST/ASTContextAllocate.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/CanonicalType.h" #include "clang/AST/CommentCommandTraits.h" @@ -22,6 +23,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" @@ -30,6 +32,7 @@ #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/AttrKinds.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -79,6 +82,7 @@ struct fltSemantics; namespace clang { +class APFixedPoint; class APValue; class ASTMutationListener; class ASTRecordLayout; @@ -92,6 +96,7 @@ class CXXMethodDecl; class CXXRecordDecl; class DiagnosticsEngine; class Expr; +class FixedPointSemantics; class MangleContext; class MangleNumberingContext; class MaterializeTemporaryExpr; @@ -148,6 +153,22 @@ struct TypeInfo { /// Holds long-lived AST nodes (such as types and decls) that can be /// referred to throughout the semantic analysis of a file. class ASTContext : public RefCountedBase<ASTContext> { +public: + /// Copy initialization expr of a __block variable and a boolean flag that + /// indicates whether the expression can throw. + struct BlockVarCopyInit { + BlockVarCopyInit() = default; + BlockVarCopyInit(Expr *CopyExpr, bool CanThrow) + : ExprAndFlag(CopyExpr, CanThrow) {} + void setExprAndFlag(Expr *CopyExpr, bool CanThrow) { + ExprAndFlag.setPointerAndInt(CopyExpr, CanThrow); + } + Expr *getCopyExpr() const { return ExprAndFlag.getPointer(); } + bool canThrow() const { return ExprAndFlag.getInt(); } + llvm::PointerIntPair<Expr *, 1, bool> ExprAndFlag; + }; + +private: friend class NestedNameSpecifier; mutable SmallVector<Type *, 0> Types; @@ -242,8 +263,8 @@ class ASTContext : public RefCountedBase<ASTContext> { /// interface. llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls; - /// Mapping from __block VarDecls to their copy initialization expr. - llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits; + /// Mapping from __block VarDecls to BlockVarCopyInit. + llvm::DenseMap<const VarDecl *, BlockVarCopyInit> BlockVarCopyInits; /// Mapping from class scope functions specialization to their /// template patterns. @@ -316,7 +337,7 @@ class ASTContext : public RefCountedBase<ASTContext> { mutable IdentifierInfo *BoolName = nullptr; /// The identifier 'NSObject'. - IdentifierInfo *NSObjectName = nullptr; + mutable IdentifierInfo *NSObjectName = nullptr; /// The identifier 'NSCopying'. IdentifierInfo *NSCopyingName = nullptr; @@ -549,26 +570,6 @@ public: IntrusiveRefCntPtr<ExternalASTSource> ExternalSource; ASTMutationListener *Listener = nullptr; - /// Contains parents of a node. - using ParentVector = llvm::SmallVector<ast_type_traits::DynTypedNode, 2>; - - /// Maps from a node to its parents. This is used for nodes that have - /// pointer identity only, which are more common and we can save space by - /// only storing a unique pointer to them. - using ParentMapPointers = - llvm::DenseMap<const void *, - llvm::PointerUnion4<const Decl *, const Stmt *, - ast_type_traits::DynTypedNode *, - ParentVector *>>; - - /// Parent map for nodes without pointer identity. We store a full - /// DynTypedNode for all keys. - using ParentMapOtherNodes = - llvm::DenseMap<ast_type_traits::DynTypedNode, - llvm::PointerUnion4<const Decl *, const Stmt *, - ast_type_traits::DynTypedNode *, - ParentVector *>>; - /// Container for either a single DynTypedNode or for an ArrayRef to /// DynTypedNode. For use with ParentMap. class DynTypedNodeList { @@ -610,7 +611,17 @@ public: } }; - /// Returns the parents of the given node. + // A traversal scope limits the parts of the AST visible to certain analyses. + // RecursiveASTVisitor::TraverseAST will only visit reachable nodes, and + // getParents() will only observe reachable parent edges. + // + // The scope is defined by a set of "top-level" declarations. + // Initially, it is the entire TU: {getTranslationUnitDecl()}. + // Changing the scope clears the parent cache, which is expensive to rebuild. + std::vector<Decl *> getTraversalScope() const { return TraversalScope; } + void setTraversalScope(const std::vector<Decl *> &); + + /// Returns the parents of the given node (within the traversal scope). /// /// Note that this will lazily compute the parents of all nodes /// and store them for later retrieval. Thus, the first call is O(n) @@ -977,7 +988,8 @@ public: /// Get the additional modules in which the definition \p Def has /// been merged. ArrayRef<Module*> getModulesWithMergedDefinition(const NamedDecl *Def) { - auto MergedIt = MergedDefModules.find(Def); + auto MergedIt = + MergedDefModules.find(cast<NamedDecl>(Def->getCanonicalDecl())); if (MergedIt == MergedDefModules.end()) return None; return MergedIt->second; @@ -1041,6 +1053,9 @@ public: CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; CanQualType OCLQueueTy, OCLReserveIDTy; CanQualType OMPArraySectionTy; +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ + CanQualType Id##Ty; +#include "clang/Basic/OpenCLExtensionTypes.def" // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand. mutable QualType AutoDeductTy; // Deduction against 'auto'. @@ -1403,7 +1418,7 @@ public: QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const; - QualType getAttributedType(AttributedType::Kind attrKind, + QualType getAttributedType(attr::Kind attrKind, QualType modifiedType, QualType equivalentType); @@ -1656,7 +1671,7 @@ public: } /// Retrieve the identifier 'NSObject'. - IdentifierInfo *getNSObjectName() { + IdentifierInfo *getNSObjectName() const { if (!NSObjectName) { NSObjectName = &Idents.get("NSObject"); } @@ -1961,6 +1976,9 @@ public: unsigned char getFixedPointScale(QualType Ty) const; unsigned char getFixedPointIBits(QualType Ty) const; + FixedPointSemantics getFixedPointSemantics(QualType Ty) const; + APFixedPoint getFixedPointMax(QualType Ty) const; + APFixedPoint getFixedPointMin(QualType Ty) const; DeclarationNameInfo getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const; @@ -2488,6 +2506,8 @@ public: unsigned getTargetAddressSpace(LangAS AS) const; + LangAS getLangASForBuiltinAddressSpace(unsigned AS) const; + /// Get target-dependent integer value for null pointer which is used for /// constant folding. uint64_t getTargetNullPointerValue(QualType QT) const; @@ -2657,12 +2677,13 @@ public: /// otherwise returns null. const ObjCInterfaceDecl *getObjContainingInterface(const NamedDecl *ND) const; - /// Set the copy inialization expression of a block var decl. - void setBlockVarCopyInits(VarDecl*VD, Expr* Init); + /// Set the copy inialization expression of a block var decl. \p CanThrow + /// indicates whether the copy expression can throw or not. + void setBlockVarCopyInit(const VarDecl* VD, Expr *CopyExpr, bool CanThrow); /// Get the copy initialization expression of the VarDecl \p VD, or /// nullptr if none exists. - Expr *getBlockVarCopyInits(const VarDecl* VD); + BlockVarCopyInit getBlockVarCopyInit(const VarDecl* VD) const; /// Allocate an uninitialized TypeSourceInfo. /// @@ -2718,7 +2739,7 @@ public: /// predicate. void forEachMultiversionedFunctionVersion( const FunctionDecl *FD, - llvm::function_ref<void(const FunctionDecl *)> Pred) const; + llvm::function_ref<void(FunctionDecl *)> Pred) const; const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD); @@ -2894,13 +2915,13 @@ private: // but we include it here so that ASTContext can quickly deallocate them. llvm::PointerIntPair<StoredDeclsMap *, 1> LastSDM; - std::unique_ptr<ParentMapPointers> PointerParents; - std::unique_ptr<ParentMapOtherNodes> OtherParents; + std::vector<Decl *> TraversalScope; + class ParentMap; + std::unique_ptr<ParentMap> Parents; std::unique_ptr<VTableContextBase> VTContext; void ReleaseDeclContextMaps(); - void ReleaseParentMapEntries(); public: enum PragmaSectionFlag : unsigned { @@ -2949,8 +2970,8 @@ inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) { /// This placement form of operator new uses the ASTContext's allocator for /// obtaining memory. /// -/// IMPORTANT: These are also declared in clang/AST/AttrIterator.h! Any changes -/// here need to also be made there. +/// IMPORTANT: These are also declared in clang/AST/ASTContextAllocate.h! +/// Any changes here need to also be made there. /// /// We intentionally avoid using a nothrow specification here so that the calls /// to this operator will not perform a null check on the result -- the @@ -2973,7 +2994,7 @@ inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) { /// allocator supports it). /// @return The allocated memory. Could be nullptr. inline void *operator new(size_t Bytes, const clang::ASTContext &C, - size_t Alignment) { + size_t Alignment /* = 8 */) { return C.Allocate(Bytes, Alignment); } @@ -3011,7 +3032,7 @@ inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) { /// allocator supports it). /// @return The allocated memory. Could be nullptr. inline void *operator new[](size_t Bytes, const clang::ASTContext& C, - size_t Alignment = 8) { + size_t Alignment /* = 8 */) { return C.Allocate(Bytes, Alignment); } diff --git a/include/clang/AST/ASTContextAllocate.h b/include/clang/AST/ASTContextAllocate.h new file mode 100644 index 000000000000..5b9eed208a4d --- /dev/null +++ b/include/clang/AST/ASTContextAllocate.h @@ -0,0 +1,38 @@ +//===- ASTContextAllocate.h - ASTContext allocate functions -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares ASTContext allocation functions separate from the main +// code in ASTContext.h. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTCONTEXTALLOCATE_H +#define LLVM_CLANG_AST_ASTCONTEXTALLOCATE_H + +#include <cstddef> + +namespace clang { + +class ASTContext; + +} // namespace clang + +// Defined in ASTContext.h +void *operator new(size_t Bytes, const clang::ASTContext &C, + size_t Alignment = 8); +void *operator new[](size_t Bytes, const clang::ASTContext &C, + size_t Alignment = 8); + +// It is good practice to pair new/delete operators. Also, MSVC gives many +// warnings if a matching delete overload is not declared, even though the +// throw() spec guarantees it will not be implicitly called. +void operator delete(void *Ptr, const clang::ASTContext &C, size_t); +void operator delete[](void *Ptr, const clang::ASTContext &C, size_t); + +#endif // LLVM_CLANG_AST_ASTCONTEXTALLOCATE_H diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h index 2534272da3a3..fe92604587ef 100644 --- a/include/clang/AST/ASTDiagnostic.h +++ b/include/clang/AST/ASTDiagnostic.h @@ -11,19 +11,9 @@ #define LLVM_CLANG_AST_ASTDIAGNOSTIC_H #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticAST.h" namespace clang { - namespace diag { - enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ - SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, -#define ASTSTART -#include "clang/Basic/DiagnosticASTKinds.inc" -#undef DIAG - NUM_BUILTIN_AST_DIAGNOSTICS - }; - } // end namespace diag - /// DiagnosticsEngine argument formatting function for diagnostics that /// involve AST nodes. /// diff --git a/include/clang/AST/ASTDumperUtils.h b/include/clang/AST/ASTDumperUtils.h new file mode 100644 index 000000000000..5e62e902b423 --- /dev/null +++ b/include/clang/AST/ASTDumperUtils.h @@ -0,0 +1,97 @@ +//===--- ASTDumperUtils.h - Printing of AST nodes -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements AST utilities for traversal down the tree. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTDUMPERUTILS_H +#define LLVM_CLANG_AST_ASTDUMPERUTILS_H + +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +// Colors used for various parts of the AST dump +// Do not use bold yellow for any text. It is hard to read on white screens. + +struct TerminalColor { + llvm::raw_ostream::Colors Color; + bool Bold; +}; + +// Red - CastColor +// Green - TypeColor +// Bold Green - DeclKindNameColor, UndeserializedColor +// Yellow - AddressColor, LocationColor +// Blue - CommentColor, NullColor, IndentColor +// Bold Blue - AttrColor +// Bold Magenta - StmtColor +// Cyan - ValueKindColor, ObjectKindColor +// Bold Cyan - ValueColor, DeclNameColor + +// Decl kind names (VarDecl, FunctionDecl, etc) +static const TerminalColor DeclKindNameColor = {llvm::raw_ostream::GREEN, true}; +// Attr names (CleanupAttr, GuardedByAttr, etc) +static const TerminalColor AttrColor = {llvm::raw_ostream::BLUE, true}; +// Statement names (DeclStmt, ImplicitCastExpr, etc) +static const TerminalColor StmtColor = {llvm::raw_ostream::MAGENTA, true}; +// Comment names (FullComment, ParagraphComment, TextComment, etc) +static const TerminalColor CommentColor = {llvm::raw_ostream::BLUE, false}; + +// Type names (int, float, etc, plus user defined types) +static const TerminalColor TypeColor = {llvm::raw_ostream::GREEN, false}; + +// Pointer address +static const TerminalColor AddressColor = {llvm::raw_ostream::YELLOW, false}; +// Source locations +static const TerminalColor LocationColor = {llvm::raw_ostream::YELLOW, false}; + +// lvalue/xvalue +static const TerminalColor ValueKindColor = {llvm::raw_ostream::CYAN, false}; +// bitfield/objcproperty/objcsubscript/vectorcomponent +static const TerminalColor ObjectKindColor = {llvm::raw_ostream::CYAN, false}; + +// Null statements +static const TerminalColor NullColor = {llvm::raw_ostream::BLUE, false}; + +// Undeserialized entities +static const TerminalColor UndeserializedColor = {llvm::raw_ostream::GREEN, + true}; + +// CastKind from CastExpr's +static const TerminalColor CastColor = {llvm::raw_ostream::RED, false}; + +// Value of the statement +static const TerminalColor ValueColor = {llvm::raw_ostream::CYAN, true}; +// Decl names +static const TerminalColor DeclNameColor = {llvm::raw_ostream::CYAN, true}; + +// Indents ( `, -. | ) +static const TerminalColor IndentColor = {llvm::raw_ostream::BLUE, false}; + +class ColorScope { + llvm::raw_ostream &OS; + const bool ShowColors; + +public: + ColorScope(llvm::raw_ostream &OS, bool ShowColors, TerminalColor Color) + : OS(OS), ShowColors(ShowColors) { + if (ShowColors) + OS.changeColor(Color.Color, Color.Bold); + } + ~ColorScope() { + if (ShowColors) + OS.resetColor(); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_ASTDUMPERUTILS_H diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h index 2e9a8775a8a2..dbb9cf35ddea 100644 --- a/include/clang/AST/ASTImporter.h +++ b/include/clang/AST/ASTImporter.h @@ -25,12 +25,15 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Error.h" #include <utility> namespace clang { class ASTContext; +class ASTImporterLookupTable; class CXXBaseSpecifier; class CXXCtorInitializer; class Decl; @@ -43,6 +46,29 @@ class TagDecl; class TypeSourceInfo; class Attr; + class ImportError : public llvm::ErrorInfo<ImportError> { + public: + /// \brief Kind of error when importing an AST component. + enum ErrorKind { + NameConflict, /// Naming ambiguity (likely ODR violation). + UnsupportedConstruct, /// Not supported node or case. + Unknown /// Other error. + }; + + ErrorKind Error; + + static char ID; + + ImportError() : Error(Unknown) { } + ImportError(const ImportError &Other) : Error(Other.Error) { } + ImportError(ErrorKind Error) : Error(Error) { } + + std::string toString() const; + + void log(raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; + }; + // \brief Returns with a list of declarations started from the canonical decl // then followed by subsequent decls in the translation unit. // This gives a canonical list for each entry in the redecl chain. @@ -55,12 +81,21 @@ class Attr; /// Imports selected nodes from one AST context into another context, /// merging AST nodes where appropriate. class ASTImporter { + friend class ASTNodeImporter; public: using NonEquivalentDeclSet = llvm::DenseSet<std::pair<Decl *, Decl *>>; using ImportedCXXBaseSpecifierMap = llvm::DenseMap<const CXXBaseSpecifier *, CXXBaseSpecifier *>; private: + + /// Pointer to the import specific lookup table, which may be shared + /// amongst several ASTImporter objects. + /// This is an externally managed resource (and should exist during the + /// lifetime of the ASTImporter object) + /// If not set then the original C/C++ lookup is used. + ASTImporterLookupTable *LookupTable = nullptr; + /// The contexts we're importing to and from. ASTContext &ToContext, &FromContext; @@ -98,9 +133,13 @@ class Attr; /// (which we have already complained about). NonEquivalentDeclSet NonEquivalentDecls; + using FoundDeclsTy = SmallVector<NamedDecl *, 2>; + FoundDeclsTy findDeclsInToCtx(DeclContext *DC, DeclarationName Name); + + void AddToLookupTable(Decl *ToD); + public: - /// Create a new AST importer. - /// + /// \param ToContext The context we'll be importing into. /// /// \param ToFileManager The file manager we'll be importing into. @@ -112,9 +151,14 @@ class Attr; /// \param MinimalImport If true, the importer will attempt to import /// as little as it can, e.g., by importing declarations as forward /// declarations that can be completed at a later point. + /// + /// \param LookupTable The importer specific lookup table which may be + /// shared amongst several ASTImporter objects. + /// If not set then the original C/C++ lookup is used. ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, - bool MinimalImport); + bool MinimalImport, + ASTImporterLookupTable *LookupTable = nullptr); virtual ~ASTImporter(); @@ -122,31 +166,60 @@ class Attr; /// to-be-completed forward declarations when possible. bool isMinimalImport() const { return Minimal; } + /// \brief Import the given object, returns the result. + /// + /// \param To Import the object into this variable. + /// \param From Object to import. + /// \return Error information (success or error). + template <typename ImportT> + LLVM_NODISCARD llvm::Error importInto(ImportT &To, const ImportT &From) { + To = Import(From); + if (From && !To) + return llvm::make_error<ImportError>(); + return llvm::Error::success(); + // FIXME: this should be the final code + //auto ToOrErr = Import(From); + //if (ToOrErr) + // To = *ToOrErr; + //return ToOrErr.takeError(); + } + /// Import the given type from the "from" context into the "to" - /// context. + /// context. A null type is imported as a null type (no error). /// - /// \returns the equivalent type in the "to" context, or a NULL type if - /// an error occurred. + /// \returns The equivalent type in the "to" context, or the import error. + llvm::Expected<QualType> Import_New(QualType FromT); + // FIXME: Remove this version. QualType Import(QualType FromT); /// Import the given type source information from the /// "from" context into the "to" context. /// - /// \returns the equivalent type source information in the "to" - /// context, or NULL if an error occurred. + /// \returns The equivalent type source information in the "to" + /// context, or the import error. + llvm::Expected<TypeSourceInfo *> Import_New(TypeSourceInfo *FromTSI); + // FIXME: Remove this version. TypeSourceInfo *Import(TypeSourceInfo *FromTSI); /// Import the given attribute from the "from" context into the /// "to" context. /// - /// \returns the equivalent attribute in the "to" context. + /// \returns The equivalent attribute in the "to" context, or the import + /// error. + llvm::Expected<Attr *> Import_New(const Attr *FromAttr); + // FIXME: Remove this version. Attr *Import(const Attr *FromAttr); /// Import the given declaration from the "from" context into the /// "to" context. /// - /// \returns the equivalent declaration in the "to" context, or a NULL type - /// if an error occurred. + /// \returns The equivalent declaration in the "to" context, or the import + /// error. + llvm::Expected<Decl *> Import_New(Decl *FromD); + llvm::Expected<Decl *> Import_New(const Decl *FromD) { + return Import_New(const_cast<Decl *>(FromD)); + } + // FIXME: Remove this version. Decl *Import(Decl *FromD); Decl *Import(const Decl *FromD) { return Import(const_cast<Decl *>(FromD)); @@ -155,104 +228,137 @@ class Attr; /// Return the copy of the given declaration in the "to" context if /// it has already been imported from the "from" context. Otherwise return /// NULL. - Decl *GetAlreadyImportedOrNull(Decl *FromD); + Decl *GetAlreadyImportedOrNull(const Decl *FromD) const; /// Import the given declaration context from the "from" /// AST context into the "to" AST context. /// /// \returns the equivalent declaration context in the "to" - /// context, or a NULL type if an error occurred. - DeclContext *ImportContext(DeclContext *FromDC); + /// context, or error value. + llvm::Expected<DeclContext *> ImportContext(DeclContext *FromDC); /// Import the given expression from the "from" context into the /// "to" context. /// - /// \returns the equivalent expression in the "to" context, or NULL if - /// an error occurred. + /// \returns The equivalent expression in the "to" context, or the import + /// error. + llvm::Expected<Expr *> Import_New(Expr *FromE); + // FIXME: Remove this version. Expr *Import(Expr *FromE); /// Import the given statement from the "from" context into the /// "to" context. /// - /// \returns the equivalent statement in the "to" context, or NULL if - /// an error occurred. + /// \returns The equivalent statement in the "to" context, or the import + /// error. + llvm::Expected<Stmt *> Import_New(Stmt *FromS); + // FIXME: Remove this version. Stmt *Import(Stmt *FromS); /// Import the given nested-name-specifier from the "from" /// context into the "to" context. /// - /// \returns the equivalent nested-name-specifier in the "to" - /// context, or NULL if an error occurred. + /// \returns The equivalent nested-name-specifier in the "to" + /// context, or the import error. + llvm::Expected<NestedNameSpecifier *> + Import_New(NestedNameSpecifier *FromNNS); + // FIXME: Remove this version. NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS); - /// Import the given nested-name-specifier from the "from" + /// Import the given nested-name-specifier-loc from the "from" /// context into the "to" context. /// - /// \returns the equivalent nested-name-specifier in the "to" - /// context. + /// \returns The equivalent nested-name-specifier-loc in the "to" + /// context, or the import error. + llvm::Expected<NestedNameSpecifierLoc> + Import_New(NestedNameSpecifierLoc FromNNS); + // FIXME: Remove this version. NestedNameSpecifierLoc Import(NestedNameSpecifierLoc FromNNS); - /// Import the goven template name from the "from" context into the - /// "to" context. + /// Import the given template name from the "from" context into the + /// "to" context, or the import error. + llvm::Expected<TemplateName> Import_New(TemplateName From); + // FIXME: Remove this version. TemplateName Import(TemplateName From); /// Import the given source location from the "from" context into /// the "to" context. /// - /// \returns the equivalent source location in the "to" context, or an - /// invalid source location if an error occurred. + /// \returns The equivalent source location in the "to" context, or the + /// import error. + llvm::Expected<SourceLocation> Import_New(SourceLocation FromLoc); + // FIXME: Remove this version. SourceLocation Import(SourceLocation FromLoc); /// Import the given source range from the "from" context into /// the "to" context. /// - /// \returns the equivalent source range in the "to" context, or an - /// invalid source location if an error occurred. + /// \returns The equivalent source range in the "to" context, or the import + /// error. + llvm::Expected<SourceRange> Import_New(SourceRange FromRange); + // FIXME: Remove this version. SourceRange Import(SourceRange FromRange); /// Import the given declaration name from the "from" /// context into the "to" context. /// - /// \returns the equivalent declaration name in the "to" context, - /// or an empty declaration name if an error occurred. + /// \returns The equivalent declaration name in the "to" context, or the + /// import error. + llvm::Expected<DeclarationName> Import_New(DeclarationName FromName); + // FIXME: Remove this version. DeclarationName Import(DeclarationName FromName); /// Import the given identifier from the "from" context /// into the "to" context. /// - /// \returns the equivalent identifier in the "to" context. + /// \returns The equivalent identifier in the "to" context. Note: It + /// returns nullptr only if the FromId was nullptr. IdentifierInfo *Import(const IdentifierInfo *FromId); /// Import the given Objective-C selector from the "from" /// context into the "to" context. /// - /// \returns the equivalent selector in the "to" context. + /// \returns The equivalent selector in the "to" context, or the import + /// error. + llvm::Expected<Selector> Import_New(Selector FromSel); + // FIXME: Remove this version. Selector Import(Selector FromSel); /// Import the given file ID from the "from" context into the /// "to" context. /// - /// \returns the equivalent file ID in the source manager of the "to" - /// context. + /// \returns The equivalent file ID in the source manager of the "to" + /// context, or the import error. + llvm::Expected<FileID> Import_New(FileID); + // FIXME: Remove this version. FileID Import(FileID); /// Import the given C++ constructor initializer from the "from" /// context into the "to" context. /// - /// \returns the equivalent initializer in the "to" context. + /// \returns The equivalent initializer in the "to" context, or the import + /// error. + llvm::Expected<CXXCtorInitializer *> + Import_New(CXXCtorInitializer *FromInit); + // FIXME: Remove this version. CXXCtorInitializer *Import(CXXCtorInitializer *FromInit); /// Import the given CXXBaseSpecifier from the "from" context into /// the "to" context. /// - /// \returns the equivalent CXXBaseSpecifier in the source manager of the - /// "to" context. + /// \returns The equivalent CXXBaseSpecifier in the source manager of the + /// "to" context, or the import error. + llvm::Expected<CXXBaseSpecifier *> + Import_New(const CXXBaseSpecifier *FromSpec); + // FIXME: Remove this version. CXXBaseSpecifier *Import(const CXXBaseSpecifier *FromSpec); /// Import the definition of the given declaration, including all of /// the declarations it contains. - /// - /// This routine is intended to be used + LLVM_NODISCARD llvm::Error ImportDefinition_New(Decl *From); + + // FIXME: Compatibility function. + // Usages of this should be changed to ImportDefinition_New. void ImportDefinition(Decl *From); /// Cope with a name conflict when importing a declaration into the @@ -333,6 +439,13 @@ class Attr; /// equivalent. bool IsStructurallyEquivalent(QualType From, QualType To, bool Complain = true); + + /// Determine the index of a field in its parent record. + /// F should be a field (or indirect field) declaration. + /// \returns The index of the field in its parent context (starting from 0). + /// On error `None` is returned (parent context is non-record). + static llvm::Optional<unsigned> getFieldIndex(Decl *F); + }; } // namespace clang diff --git a/include/clang/AST/ASTImporterLookupTable.h b/include/clang/AST/ASTImporterLookupTable.h new file mode 100644 index 000000000000..14cafe817ddc --- /dev/null +++ b/include/clang/AST/ASTImporterLookupTable.h @@ -0,0 +1,75 @@ +//===- ASTImporterLookupTable.h - ASTImporter specific lookup--*- 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 ASTImporterLookupTable class which implements a +// lookup procedure for the import mechanism. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTIMPORTERLOOKUPTABLE_H +#define LLVM_CLANG_AST_ASTIMPORTERLOOKUPTABLE_H + +#include "clang/AST/DeclBase.h" // lookup_result +#include "clang/AST/DeclarationName.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { + +class ASTContext; +class NamedDecl; +class DeclContext; + +// There are certain cases when normal C/C++ lookup (localUncachedLookup) +// does not find AST nodes. E.g.: +// Example 1: +// template <class T> +// struct X { +// friend void foo(); // this is never found in the DC of the TU. +// }; +// Example 2: +// // The fwd decl to Foo is not found in the lookupPtr of the DC of the +// // translation unit decl. +// // Here we could find the node by doing a traverse throught the list of +// // the Decls in the DC, but that would not scale. +// struct A { struct Foo *p; }; +// This is a severe problem because the importer decides if it has to create a +// new Decl or not based on the lookup results. +// To overcome these cases we need an importer specific lookup table which +// holds every node and we are not interested in any C/C++ specific visibility +// considerations. Simply, we must know if there is an existing Decl in a +// given DC. Once we found it then we can handle any visibility related tasks. +class ASTImporterLookupTable { + + // We store a list of declarations for each name. + // And we collect these lists for each DeclContext. + // We could have a flat map with (DeclContext, Name) tuple as key, but a two + // level map seems easier to handle. + using DeclList = llvm::SmallSetVector<NamedDecl *, 2>; + using NameMap = llvm::SmallDenseMap<DeclarationName, DeclList, 4>; + using DCMap = llvm::DenseMap<DeclContext *, NameMap>; + + void add(DeclContext *DC, NamedDecl *ND); + void remove(DeclContext *DC, NamedDecl *ND); + + DCMap LookupTable; + +public: + ASTImporterLookupTable(TranslationUnitDecl &TU); + void add(NamedDecl *ND); + void remove(NamedDecl *ND); + using LookupResult = DeclList; + LookupResult lookup(DeclContext *DC, DeclarationName Name) const; + void dump(DeclContext *DC) const; + void dump() const; +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_ASTIMPORTERLOOKUPTABLE_H diff --git a/include/clang/AST/ASTStructuralEquivalence.h b/include/clang/AST/ASTStructuralEquivalence.h index d32f87d43e04..f8847505bc72 100644 --- a/include/clang/AST/ASTStructuralEquivalence.h +++ b/include/clang/AST/ASTStructuralEquivalence.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H #define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H +#include "clang/AST/DeclBase.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" @@ -114,8 +115,19 @@ struct StructuralEquivalenceContext { private: /// Finish checking all of the structural equivalences. /// - /// \returns true if an error occurred, false otherwise. + /// \returns true if the equivalence check failed (non-equivalence detected), + /// false if equivalence was detected. bool Finish(); + + /// Check for common properties at Finish. + /// \returns true if D1 and D2 may be equivalent, + /// false if they are for sure not. + bool CheckCommonEquivalence(Decl *D1, Decl *D2); + + /// Check for class dependent properties at Finish. + /// \returns true if D1 and D2 may be equivalent, + /// false if they are for sure not. + bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2); }; } // namespace clang diff --git a/include/clang/AST/ASTVector.h b/include/clang/AST/ASTVector.h index 80cd6b7007a6..51de119f080e 100644 --- a/include/clang/AST/ASTVector.h +++ b/include/clang/AST/ASTVector.h @@ -18,6 +18,7 @@ #ifndef LLVM_CLANG_AST_ASTVECTOR_H #define LLVM_CLANG_AST_ASTVECTOR_H +#include "clang/AST/ASTContextAllocate.h" #include "llvm/ADT/PointerIntPair.h" #include <algorithm> #include <cassert> diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 20922742f687..3a319326d269 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_ATTR_H #define LLVM_CLANG_AST_ATTR_H +#include "clang/AST/ASTContextAllocate.h" // For Attrs.inc #include "clang/AST/AttrIterator.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" @@ -113,6 +114,19 @@ public: void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const; }; +class TypeAttr : public Attr { +protected: + TypeAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, + bool IsLateParsed) + : Attr(AK, R, SpellingListIndex, IsLateParsed) {} + +public: + static bool classof(const Attr *A) { + return A->getKind() >= attr::FirstTypeAttr && + A->getKind() <= attr::LastTypeAttr; + } +}; + class StmtAttr : public Attr { protected: StmtAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, diff --git a/include/clang/AST/AttrIterator.h b/include/clang/AST/AttrIterator.h index 2087ecc0e70c..43ad1c931967 100644 --- a/include/clang/AST/AttrIterator.h +++ b/include/clang/AST/AttrIterator.h @@ -26,25 +26,6 @@ namespace clang { class ASTContext; class Attr; -} // namespace clang - -// Defined in ASTContext.h -void *operator new(size_t Bytes, const clang::ASTContext &C, - size_t Alignment = 8); - -// FIXME: Being forced to not have a default argument here due to redeclaration -// rules on default arguments sucks -void *operator new[](size_t Bytes, const clang::ASTContext &C, - size_t Alignment); - -// It is good practice to pair new/delete operators. Also, MSVC gives many -// warnings if a matching delete overload is not declared, even though the -// throw() spec guarantees it will not be implicitly called. -void operator delete(void *Ptr, const clang::ASTContext &C, size_t); -void operator delete[](void *Ptr, const clang::ASTContext &C, size_t); - -namespace clang { - /// AttrVec - A vector of Attr, which is how they are stored on the AST. using AttrVec = SmallVector<Attr *, 4>; diff --git a/include/clang/AST/AttrVisitor.h b/include/clang/AST/AttrVisitor.h new file mode 100644 index 000000000000..867f9e7ad18d --- /dev/null +++ b/include/clang/AST/AttrVisitor.h @@ -0,0 +1,76 @@ +//===- AttrVisitor.h - Visitor for Attr subclasses --------------*- 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 AttrVisitor interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ATTRVISITOR_H +#define LLVM_CLANG_AST_ATTRVISITOR_H + +#include "clang/AST/Attr.h" + +namespace clang { + +namespace attrvisitor { + +/// A simple visitor class that helps create attribute visitors. +template <template <typename> class Ptr, typename ImplClass, + typename RetTy = void, class... ParamTys> +class Base { +public: +#define PTR(CLASS) typename Ptr<CLASS>::type +#define DISPATCH(NAME) \ + return static_cast<ImplClass *>(this)->Visit##NAME(static_cast<PTR(NAME)>(A)) + + RetTy Visit(PTR(Attr) A) { + switch (A->getKind()) { + +#define ATTR(NAME) \ + case attr::NAME: \ + DISPATCH(NAME##Attr); +#include "clang/Basic/AttrList.inc" + } + llvm_unreachable("Attr that isn't part of AttrList.inc!"); + } + + // If the implementation chooses not to implement a certain visit + // method, fall back to the parent. +#define ATTR(NAME) \ + RetTy Visit##NAME##Attr(PTR(NAME##Attr) A) { DISPATCH(Attr); } +#include "clang/Basic/AttrList.inc" + + RetTy VisitAttr(PTR(Attr)) { return RetTy(); } + +#undef PTR +#undef DISPATCH +}; + +} // namespace attrvisitor + +/// A simple visitor class that helps create attribute visitors. +/// +/// This class does not preserve constness of Attr pointers (see +/// also ConstAttrVisitor). +template <typename ImplClass, typename RetTy = void, typename... ParamTys> +class AttrVisitor : public attrvisitor::Base<std::add_pointer, ImplClass, RetTy, + ParamTys...> {}; + +/// A simple visitor class that helps create attribute visitors. +/// +/// This class preserves constness of Attr pointers (see also +/// AttrVisitor). +template <typename ImplClass, typename RetTy = void, typename... ParamTys> +class ConstAttrVisitor + : public attrvisitor::Base<llvm::make_const_ptr, ImplClass, RetTy, + ParamTys...> {}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_ATTRVISITOR_H diff --git a/include/clang/AST/BaseSubobject.h b/include/clang/AST/BaseSubobject.h index 2b702c76b2fa..8fd4ac69ebd6 100644 --- a/include/clang/AST/BaseSubobject.h +++ b/include/clang/AST/BaseSubobject.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_BASESUBOBJECT_H #include "clang/AST/CharUnits.h" +#include "clang/AST/DeclCXX.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/type_traits.h" #include <cstdint> diff --git a/include/clang/AST/CMakeLists.txt b/include/clang/AST/CMakeLists.txt index 942d08d585fe..da16987141c2 100644 --- a/include/clang/AST/CMakeLists.txt +++ b/include/clang/AST/CMakeLists.txt @@ -8,10 +8,15 @@ clang_tablegen(AttrImpl.inc -gen-clang-attr-impl SOURCE ../Basic/Attr.td TARGET ClangAttrImpl) -clang_tablegen(AttrDump.inc -gen-clang-attr-dump +clang_tablegen(AttrTextNodeDump.inc -gen-clang-attr-text-node-dump -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ SOURCE ../Basic/Attr.td - TARGET ClangAttrDump) + TARGET ClangAttrTextDump) + +clang_tablegen(AttrNodeTraverse.inc -gen-clang-attr-node-traverse + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrTraverse) clang_tablegen(AttrVisitor.inc -gen-clang-attr-ast-visitor -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 0e738da43ad4..c2f01e7d5460 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -510,7 +510,7 @@ struct CanProxyAdaptor<FunctionProtoType> } LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getTypeQuals) using param_type_iterator = CanTypeIterator<FunctionProtoType::param_type_iterator>; diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h index f5538dec2a14..1b590562e152 100644 --- a/include/clang/AST/Comment.h +++ b/include/clang/AST/Comment.h @@ -215,13 +215,9 @@ public: SourceRange getSourceRange() const LLVM_READONLY { return Range; } - SourceLocation getLocStart() const LLVM_READONLY { - return Range.getBegin(); - } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return Range.getEnd(); - } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } SourceLocation getLocation() const LLVM_READONLY { return Loc; } @@ -351,8 +347,7 @@ public: } SourceRange getCommandNameRange() const { - return SourceRange(getLocStart().getLocWithOffset(-1), - getLocEnd()); + return SourceRange(getBeginLoc().getLocWithOffset(-1), getEndLoc()); } RenderKind getRenderKind() const { @@ -566,9 +561,9 @@ public: ParagraphCommentBits.IsWhitespaceValid = false; - setSourceRange(SourceRange(Content.front()->getLocStart(), - Content.back()->getLocEnd())); - setLocation(Content.front()->getLocStart()); + setSourceRange(SourceRange(Content.front()->getBeginLoc(), + Content.back()->getEndLoc())); + setLocation(Content.front()->getBeginLoc()); } static bool classof(const Comment *C) { @@ -662,13 +657,13 @@ public: } SourceLocation getCommandNameBeginLoc() const { - return getLocStart().getLocWithOffset(1); + return getBeginLoc().getLocWithOffset(1); } SourceRange getCommandNameRange(const CommandTraits &Traits) const { StringRef Name = getCommandName(Traits); return SourceRange(getCommandNameBeginLoc(), - getLocStart().getLocWithOffset(1 + Name.size())); + getBeginLoc().getLocWithOffset(1 + Name.size())); } unsigned getNumArgs() const { @@ -688,7 +683,7 @@ public: if (Args.size() > 0) { SourceLocation NewLocEnd = Args.back().Range.getEnd(); if (NewLocEnd.isValid()) - setSourceRange(SourceRange(getLocStart(), NewLocEnd)); + setSourceRange(SourceRange(getBeginLoc(), NewLocEnd)); } } @@ -702,9 +697,9 @@ public: void setParagraph(ParagraphComment *PC) { Paragraph = PC; - SourceLocation NewLocEnd = PC->getLocEnd(); + SourceLocation NewLocEnd = PC->getEndLoc(); if (NewLocEnd.isValid()) - setSourceRange(SourceRange(getLocStart(), NewLocEnd)); + setSourceRange(SourceRange(getBeginLoc(), NewLocEnd)); } CommandMarkerKind getCommandMarker() const LLVM_READONLY { @@ -978,7 +973,7 @@ public: } SourceRange getTextRange() const { - return SourceRange(TextBegin, getLocEnd()); + return SourceRange(TextBegin, getEndLoc()); } }; @@ -1105,9 +1100,9 @@ public: if (Blocks.empty()) return; - setSourceRange(SourceRange(Blocks.front()->getLocStart(), - Blocks.back()->getLocEnd())); - setLocation(Blocks.front()->getLocStart()); + setSourceRange( + SourceRange(Blocks.front()->getBeginLoc(), Blocks.back()->getEndLoc())); + setLocation(Blocks.front()->getBeginLoc()); } static bool classof(const Comment *C) { diff --git a/include/clang/AST/CommentDiagnostic.h b/include/clang/AST/CommentDiagnostic.h index f3a209bf6e7c..b9816f1a8e62 100644 --- a/include/clang/AST/CommentDiagnostic.h +++ b/include/clang/AST/CommentDiagnostic.h @@ -10,20 +10,7 @@ #ifndef LLVM_CLANG_AST_COMMENTDIAGNOSTIC_H #define LLVM_CLANG_AST_COMMENTDIAGNOSTIC_H -#include "clang/Basic/Diagnostic.h" - -namespace clang { - namespace diag { - enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ - SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, -#define COMMENTSTART -#include "clang/Basic/DiagnosticCommentKinds.inc" -#undef DIAG - NUM_BUILTIN_COMMENT_DIAGNOSTICS - }; - } // end namespace diag -} // end namespace clang +#include "clang/Basic/DiagnosticComment.h" #endif diff --git a/include/clang/AST/CommentVisitor.h b/include/clang/AST/CommentVisitor.h index d1cc2d0a4e5e..e37e9d6cd299 100644 --- a/include/clang/AST/CommentVisitor.h +++ b/include/clang/AST/CommentVisitor.h @@ -11,22 +11,21 @@ #define LLVM_CLANG_AST_COMMENTVISITOR_H #include "clang/AST/Comment.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" namespace clang { namespace comments { - -template <typename T> struct make_ptr { using type = T *; }; -template <typename T> struct make_const_ptr { using type = const T *; }; - -template<template <typename> class Ptr, typename ImplClass, typename RetTy=void> +template <template <typename> class Ptr, typename ImplClass, + typename RetTy = void, class... ParamTys> class CommentVisitorBase { public: #define PTR(CLASS) typename Ptr<CLASS>::type -#define DISPATCH(NAME, CLASS) \ - return static_cast<ImplClass*>(this)->visit ## NAME(static_cast<PTR(CLASS)>(C)) +#define DISPATCH(NAME, CLASS) \ + return static_cast<ImplClass *>(this)->visit##NAME( \ + static_cast<PTR(CLASS)>(C), std::forward<ParamTys>(P)...) - RetTy visit(PTR(Comment) C) { + RetTy visit(PTR(Comment) C, ParamTys... P) { if (!C) return RetTy(); @@ -44,25 +43,26 @@ public: // If the derived class does not implement a certain Visit* method, fall back // on Visit* method for the superclass. #define ABSTRACT_COMMENT(COMMENT) COMMENT -#define COMMENT(CLASS, PARENT) \ - RetTy visit ## CLASS(PTR(CLASS) C) { DISPATCH(PARENT, PARENT); } +#define COMMENT(CLASS, PARENT) \ + RetTy visit##CLASS(PTR(CLASS) C, ParamTys... P) { DISPATCH(PARENT, PARENT); } #include "clang/AST/CommentNodes.inc" #undef ABSTRACT_COMMENT #undef COMMENT - RetTy visitComment(PTR(Comment) C) { return RetTy(); } + RetTy visitComment(PTR(Comment) C, ParamTys... P) { return RetTy(); } #undef PTR #undef DISPATCH }; -template<typename ImplClass, typename RetTy=void> -class CommentVisitor : - public CommentVisitorBase<make_ptr, ImplClass, RetTy> {}; +template <typename ImplClass, typename RetTy = void, class... ParamTys> +class CommentVisitor : public CommentVisitorBase<std::add_pointer, ImplClass, + RetTy, ParamTys...> {}; -template<typename ImplClass, typename RetTy=void> -class ConstCommentVisitor : - public CommentVisitorBase<make_const_ptr, ImplClass, RetTy> {}; +template <typename ImplClass, typename RetTy = void, class... ParamTys> +class ConstCommentVisitor + : public CommentVisitorBase<llvm::make_const_ptr, ImplClass, RetTy, + ParamTys...> {}; } // namespace comments } // namespace clang diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index ebdb2890daf5..de2765391f0f 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_DECL_H #include "clang/AST/APValue.h" +#include "clang/AST/ASTContextAllocate.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" @@ -81,7 +82,7 @@ class VarTemplateDecl; /// A client can read the relevant info using TypeLoc wrappers, e.g: /// @code /// TypeLoc TL = TypeSourceInfo->getTypeLoc(); -/// TL.getStartLoc().print(OS, SrcMgr); +/// TL.getBeginLoc().print(OS, SrcMgr); /// @endcode class alignas(8) TypeSourceInfo { // Contains a memory block after the class, used for type source information, @@ -614,7 +615,7 @@ public: return SourceRange(LocStart, RBraceLoc); } - SourceLocation getLocStart() const LLVM_READONLY { return LocStart; } + SourceLocation getBeginLoc() const LLVM_READONLY { return LocStart; } SourceLocation getRBraceLoc() const { return RBraceLoc; } void setLocStart(SourceLocation L) { LocStart = L; } void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } @@ -735,7 +736,7 @@ public: SourceRange getSourceRange() const override LLVM_READONLY; - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getBeginLoc() const LLVM_READONLY { return getOuterLocStart(); } @@ -866,8 +867,12 @@ private: unsigned SClass : 3; unsigned TSCSpec : 2; unsigned InitStyle : 2; + + /// Whether this variable is an ARC pseudo-__strong variable; see + /// isARCPseudoStrong() for details. + unsigned ARCPseudoStrong : 1; }; - enum { NumVarDeclBits = 7 }; + enum { NumVarDeclBits = 8 }; protected: enum { NumParameterIndexBits = 8 }; @@ -940,10 +945,6 @@ protected: /// Whether this variable is the for-in loop declaration in Objective-C. unsigned ObjCForDecl : 1; - /// Whether this variable is an ARC pseudo-__strong - /// variable; see isARCPseudoStrong() for details. - unsigned ARCPseudoStrong : 1; - /// Whether this variable is (C++1z) inline. unsigned IsInline : 1; @@ -965,6 +966,8 @@ protected: /// Defines kind of the ImplicitParamDecl: 'this', 'self', 'vtt', '_cmd' or /// something else. unsigned ImplicitParamKind : 3; + + unsigned EscapingByref : 1; }; union { @@ -1347,17 +1350,15 @@ public: NonParmVarDeclBits.ObjCForDecl = FRD; } - /// Determine whether this variable is an ARC pseudo-__strong - /// variable. A pseudo-__strong variable has a __strong-qualified - /// type but does not actually retain the object written into it. - /// Generally such variables are also 'const' for safety. - bool isARCPseudoStrong() const { - return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.ARCPseudoStrong; - } - void setARCPseudoStrong(bool ps) { - assert(!isa<ParmVarDecl>(this)); - NonParmVarDeclBits.ARCPseudoStrong = ps; - } + /// Determine whether this variable is an ARC pseudo-__strong variable. A + /// pseudo-__strong variable has a __strong-qualified type but does not + /// actually retain the object written into it. Generally such variables are + /// also 'const' for safety. There are 3 cases where this will be set, 1) if + /// the variable is annotated with the objc_externally_retained attribute, 2) + /// if its 'self' in a non-init method, or 3) if its the variable in an for-in + /// loop. + bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; } + void setARCPseudoStrong(bool PS) { VarDeclBits.ARCPseudoStrong = PS; } /// Whether this variable is (C++1z) inline. bool isInline() const { @@ -1407,6 +1408,19 @@ public: NonParmVarDeclBits.PreviousDeclInSameBlockScope = Same; } + /// Indicates the capture is a __block variable that is captured by a block + /// that can potentially escape (a block for which BlockDecl::doesNotEscape + /// returns false). + bool isEscapingByref() const; + + /// Indicates the capture is a __block variable that is never captured by an + /// escaping block. + bool isNonEscapingByref() const; + + void setEscapingByref() { + NonParmVarDeclBits.EscapingByref = true; + } + /// Retrieve the variable declaration from which this variable could /// be instantiated, if it is an instantiation (rather than a non-template). VarDecl *getTemplateInstantiationPattern() const; @@ -1461,6 +1475,9 @@ public: // has no definition within this source file. bool isKnownToBeDefined() const; + /// Do we need to emit an exit-time destructor for this variable? + bool isNoDestroy(const ASTContext &) const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; } @@ -1701,6 +1718,13 @@ private: unsigned getParameterIndexLarge() const; }; +enum class MultiVersionKind { + None, + Target, + CPUSpecific, + CPUDispatch +}; + /// Represents a function declaration or definition. /// /// Since a given function can be declared several times in a program, @@ -1711,8 +1735,11 @@ private: /// 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, +class FunctionDecl : public DeclaratorDecl, + public DeclContext, public Redeclarable<FunctionDecl> { + // This class stores some data in DeclContext::FunctionDeclBits + // to save some space. Use the provided accessors to access it. public: /// The kind of templated function a FunctionDecl can be. enum TemplatedKind { @@ -1731,64 +1758,6 @@ private: LazyDeclStmtPtr Body; - // FIXME: This can be packed into the bitfields in DeclContext. - // NOTE: VC++ packs bitfields poorly if the types differ. - unsigned SClass : 3; - unsigned IsInline : 1; - unsigned IsInlineSpecified : 1; - -protected: - // This is shared by CXXConstructorDecl, CXXConversionDecl, and - // CXXDeductionGuideDecl. - unsigned IsExplicitSpecified : 1; - -private: - unsigned IsVirtualAsWritten : 1; - unsigned IsPure : 1; - unsigned HasInheritedPrototype : 1; - unsigned HasWrittenPrototype : 1; - unsigned IsDeleted : 1; - unsigned IsTrivial : 1; // sunk from CXXMethodDecl - - /// This flag indicates whether this function is trivial for the purpose of - /// calls. This is meaningful only when this function is a copy/move - /// constructor or a destructor. - unsigned IsTrivialForCall : 1; - - unsigned IsDefaulted : 1; // sunk from CXXMethoDecl - unsigned IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl - unsigned HasImplicitReturnZero : 1; - unsigned IsLateTemplateParsed : 1; - unsigned IsConstexpr : 1; - unsigned InstantiationIsPending : 1; - - /// Indicates if the function uses __try. - unsigned UsesSEHTry : 1; - - /// Indicates if the function was a definition but its body was - /// skipped. - unsigned HasSkippedBody : 1; - - /// Indicates if the function declaration will have a body, once we're done - /// parsing it. - unsigned WillHaveBody : 1; - - /// Indicates that this function is a multiversioned function using attribute - /// 'target'. - unsigned IsMultiVersion : 1; - -protected: - /// [C++17] Only used by CXXDeductionGuideDecl. Declared here to avoid - /// increasing the size of CXXDeductionGuideDecl by the size of an unsigned - /// int as opposed to adding a single bit to FunctionDecl. - /// Indicates that the Deduction Guide is the implicitly generated 'copy - /// deduction candidate' (is used during overload resolution). - unsigned IsCopyDeductionCandidate : 1; - -private: - - /// Store the ODRHash after first calculation. - unsigned HasODRHash : 1; unsigned ODRHash; /// End part of this FunctionDecl's source range. @@ -1858,25 +1827,22 @@ private: void setParams(ASTContext &C, ArrayRef<ParmVarDecl *> NewParamInfo); + // This is unfortunately needed because ASTDeclWriter::VisitFunctionDecl + // need to access this bit but we want to avoid making ASTDeclWriter + // a friend of FunctionDeclBitfields just for this. + bool isDeletedBit() const { return FunctionDeclBits.IsDeleted; } + + /// Whether an ODRHash has been stored. + bool hasODRHash() const { return FunctionDeclBits.HasODRHash; } + + /// State that an ODRHash has been stored. + void setHasODRHash(bool B = true) { FunctionDeclBits.HasODRHash = B; } + protected: FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified, - bool isConstexprSpecified) - : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, - StartLoc), - DeclContext(DK), redeclarable_base(C), SClass(S), - IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified), - IsExplicitSpecified(false), IsVirtualAsWritten(false), IsPure(false), - HasInheritedPrototype(false), HasWrittenPrototype(true), - IsDeleted(false), IsTrivial(false), IsTrivialForCall(false), - IsDefaulted(false), - IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), - IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), - InstantiationIsPending(false), UsesSEHTry(false), HasSkippedBody(false), - WillHaveBody(false), IsMultiVersion(false), - IsCopyDeductionCandidate(false), HasODRHash(false), ODRHash(0), - EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {} + bool isConstexprSpecified); using redeclarable_base = Redeclarable<FunctionDecl>; @@ -2015,13 +1981,13 @@ public: /// This does not determine whether the function has been defined (e.g., in a /// previous definition); for that information, use isDefined. bool isThisDeclarationADefinition() const { - return IsDeleted || IsDefaulted || Body || HasSkippedBody || - IsLateTemplateParsed || WillHaveBody || hasDefiningAttr(); + return isDeletedAsWritten() || isDefaulted() || Body || hasSkippedBody() || + isLateTemplateParsed() || willHaveBody() || hasDefiningAttr(); } /// Returns whether this specific declaration of the function has a body. bool doesThisDeclarationHaveABody() const { - return Body || IsLateTemplateParsed; + return Body || isLateTemplateParsed(); } void setBody(Stmt *B); @@ -2031,62 +1997,102 @@ public: bool isVariadic() const; /// Whether this function is marked as virtual explicitly. - bool isVirtualAsWritten() const { return IsVirtualAsWritten; } - void setVirtualAsWritten(bool V) { IsVirtualAsWritten = V; } + bool isVirtualAsWritten() const { + return FunctionDeclBits.IsVirtualAsWritten; + } + + /// State that this function is marked as virtual explicitly. + void setVirtualAsWritten(bool V) { FunctionDeclBits.IsVirtualAsWritten = V; } /// Whether this virtual function is pure, i.e. makes the containing class /// abstract. - bool isPure() const { return IsPure; } + bool isPure() const { return FunctionDeclBits.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; } + bool isLateTemplateParsed() const { + return FunctionDeclBits.IsLateTemplateParsed; + } + + /// State that this templated function will be late parsed. + void setLateTemplateParsed(bool ILT = true) { + FunctionDeclBits.IsLateTemplateParsed = ILT; + } /// Whether this function is "trivial" in some specialized C++ senses. /// Can only be true for default constructors, copy constructors, /// copy assignment operators, and destructors. Not meaningful until /// the class has been fully built by Sema. - bool isTrivial() const { return IsTrivial; } - void setTrivial(bool IT) { IsTrivial = IT; } + bool isTrivial() const { return FunctionDeclBits.IsTrivial; } + void setTrivial(bool IT) { FunctionDeclBits.IsTrivial = IT; } - bool isTrivialForCall() const { return IsTrivialForCall; } - void setTrivialForCall(bool IT) { IsTrivialForCall = IT; } + bool isTrivialForCall() const { return FunctionDeclBits.IsTrivialForCall; } + void setTrivialForCall(bool IT) { FunctionDeclBits.IsTrivialForCall = IT; } /// Whether this function is defaulted per C++0x. Only valid for /// special member functions. - bool isDefaulted() const { return IsDefaulted; } - void setDefaulted(bool D = true) { IsDefaulted = D; } + bool isDefaulted() const { return FunctionDeclBits.IsDefaulted; } + void setDefaulted(bool D = true) { FunctionDeclBits.IsDefaulted = D; } /// Whether this function is explicitly defaulted per C++0x. Only valid /// for special member functions. - bool isExplicitlyDefaulted() const { return IsExplicitlyDefaulted; } - void setExplicitlyDefaulted(bool ED = true) { IsExplicitlyDefaulted = ED; } + bool isExplicitlyDefaulted() const { + return FunctionDeclBits.IsExplicitlyDefaulted; + } + + /// State that this function is explicitly defaulted per C++0x. Only valid + /// for special member functions. + void setExplicitlyDefaulted(bool ED = true) { + FunctionDeclBits.IsExplicitlyDefaulted = ED; + } /// Whether falling off this function implicitly returns null/zero. /// If a more specific implicit return value is required, front-ends /// should synthesize the appropriate return statements. - bool hasImplicitReturnZero() const { return HasImplicitReturnZero; } - void setHasImplicitReturnZero(bool IRZ) { HasImplicitReturnZero = IRZ; } + bool hasImplicitReturnZero() const { + return FunctionDeclBits.HasImplicitReturnZero; + } + + /// State that falling off this function implicitly returns null/zero. + /// If a more specific implicit return value is required, front-ends + /// should synthesize the appropriate return statements. + void setHasImplicitReturnZero(bool IRZ) { + FunctionDeclBits.HasImplicitReturnZero = IRZ; + } /// Whether this function has a prototype, either because one /// was explicitly written or because it was "inherited" by merging /// a declaration without a prototype with a declaration that has a /// prototype. bool hasPrototype() const { - return HasWrittenPrototype || HasInheritedPrototype; + return hasWrittenPrototype() || hasInheritedPrototype(); } - bool hasWrittenPrototype() const { return HasWrittenPrototype; } + /// Whether this function has a written prototype. + bool hasWrittenPrototype() const { + return FunctionDeclBits.HasWrittenPrototype; + } + + /// State that this function has a written prototype. + void setHasWrittenPrototype(bool P = true) { + FunctionDeclBits.HasWrittenPrototype = P; + } /// Whether this function inherited its prototype from a /// previous declaration. - bool hasInheritedPrototype() const { return HasInheritedPrototype; } - void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; } + bool hasInheritedPrototype() const { + return FunctionDeclBits.HasInheritedPrototype; + } + + /// State that this function inherited its prototype from a + /// previous declaration. + void setHasInheritedPrototype(bool P = true) { + FunctionDeclBits.HasInheritedPrototype = P; + } /// Whether this is a (C++11) constexpr function or constexpr constructor. - bool isConstexpr() const { return IsConstexpr; } - void setConstexpr(bool IC) { IsConstexpr = IC; } + bool isConstexpr() const { return FunctionDeclBits.IsConstexpr; } + void setConstexpr(bool IC) { FunctionDeclBits.IsConstexpr = IC; } /// Whether the instantiation of this function is pending. /// This bit is set when the decision to instantiate this function is made @@ -2094,12 +2100,19 @@ public: /// cases where instantiation did not happen because the template definition /// was not seen in this TU. This bit remains set in those cases, under the /// assumption that the instantiation will happen in some other TU. - bool instantiationIsPending() const { return InstantiationIsPending; } - void setInstantiationIsPending(bool IC) { InstantiationIsPending = IC; } + bool instantiationIsPending() const { + return FunctionDeclBits.InstantiationIsPending; + } + + /// State that the instantiation of this function is pending. + /// (see instantiationIsPending) + void setInstantiationIsPending(bool IC) { + FunctionDeclBits.InstantiationIsPending = IC; + } /// Indicates the function uses __try. - bool usesSEHTry() const { return UsesSEHTry; } - void setUsesSEHTry(bool UST) { UsesSEHTry = UST; } + bool usesSEHTry() const { return FunctionDeclBits.UsesSEHTry; } + void setUsesSEHTry(bool UST) { FunctionDeclBits.UsesSEHTry = UST; } /// Whether this function has been deleted. /// @@ -2120,9 +2133,15 @@ public: /// }; /// @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; } + bool isDeleted() const { + return getCanonicalDecl()->FunctionDeclBits.IsDeleted; + } + + bool isDeletedAsWritten() const { + return FunctionDeclBits.IsDeleted && !isDefaulted(); + } + + void setDeletedAsWritten(bool D = true) { FunctionDeclBits.IsDeleted = D; } /// Determines whether this function is "main", which is the /// entry point into an executable program. @@ -2193,22 +2212,32 @@ public: bool isNoReturn() const; /// True if the function was a definition but its body was skipped. - bool hasSkippedBody() const { return HasSkippedBody; } - void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; } + bool hasSkippedBody() const { return FunctionDeclBits.HasSkippedBody; } + void setHasSkippedBody(bool Skipped = true) { + FunctionDeclBits.HasSkippedBody = Skipped; + } /// True if this function will eventually have a body, once it's fully parsed. - bool willHaveBody() const { return WillHaveBody; } - void setWillHaveBody(bool V = true) { WillHaveBody = V; } + bool willHaveBody() const { return FunctionDeclBits.WillHaveBody; } + void setWillHaveBody(bool V = true) { FunctionDeclBits.WillHaveBody = V; } /// True if this function is considered a multiversioned function. - bool isMultiVersion() const { return getCanonicalDecl()->IsMultiVersion; } + bool isMultiVersion() const { + return getCanonicalDecl()->FunctionDeclBits.IsMultiVersion; + } /// Sets the multiversion state for this declaration and all of its /// redeclarations. void setIsMultiVersion(bool V = true) { - getCanonicalDecl()->IsMultiVersion = V; + getCanonicalDecl()->FunctionDeclBits.IsMultiVersion = V; } + /// Gets the kind of multiversioning attribute this declaration has. Note that + /// this can return a value even if the function is not multiversion, such as + /// the case of 'target'. + MultiVersionKind getMultiVersionKind() const; + + /// True if this function is a multiversioned dispatch function as a part of /// the cpu_specific/cpu_dispatch functionality. bool isCPUDispatchMultiVersion() const; @@ -2216,6 +2245,10 @@ public: /// part of the cpu_specific/cpu_dispatch functionality. bool isCPUSpecificMultiVersion() const; + /// True if this function is a multiversioned dispatch function as a part of + /// the target functionality. + bool isTargetMultiVersion() const; + void setPreviousDeclaration(FunctionDecl * PrevDecl); FunctionDecl *getCanonicalDecl() override; @@ -2267,8 +2300,7 @@ public: unsigned getMinRequiredArguments() const; QualType getReturnType() const { - assert(getType()->getAs<FunctionType>() && "Expected a FunctionType!"); - return getType()->getAs<FunctionType>()->getReturnType(); + return getType()->castAs<FunctionType>()->getReturnType(); } /// Attempt to compute an informative source range covering the @@ -2276,47 +2308,62 @@ public: /// limited representation in the AST. SourceRange getReturnTypeSourceRange() const; + /// Get the declared return type, which may differ from the actual return + /// type if the return type is deduced. + QualType getDeclaredReturnType() const { + auto *TSI = getTypeSourceInfo(); + QualType T = TSI ? TSI->getType() : getType(); + return T->castAs<FunctionType>()->getReturnType(); + } + /// Attempt to compute an informative source range covering the /// function exception specification, if any. SourceRange getExceptionSpecSourceRange() const; /// Determine the type of an expression that calls this function. QualType getCallResultType() const { - assert(getType()->getAs<FunctionType>() && "Expected a FunctionType!"); - return getType()->getAs<FunctionType>()->getCallResultType(getASTContext()); + return getType()->castAs<FunctionType>()->getCallResultType( + getASTContext()); } - /// Returns the WarnUnusedResultAttr that is either declared on this - /// function, or its return type declaration. - const Attr *getUnusedResultAttr() const; - - /// Returns true if this function or its return type has the - /// warn_unused_result attribute. - bool hasUnusedResultAttr() const { return getUnusedResultAttr() != nullptr; } - /// Returns the storage class as written in the source. For the /// computed linkage of symbol, see getLinkage. - StorageClass getStorageClass() const { return StorageClass(SClass); } + StorageClass getStorageClass() const { + return static_cast<StorageClass>(FunctionDeclBits.SClass); + } + + /// Sets the storage class as written in the source. + void setStorageClass(StorageClass SClass) { + FunctionDeclBits.SClass = SClass; + } /// Determine whether the "inline" keyword was specified for this /// function. - bool isInlineSpecified() const { return IsInlineSpecified; } + bool isInlineSpecified() const { return FunctionDeclBits.IsInlineSpecified; } /// Set whether the "inline" keyword was specified for this function. void setInlineSpecified(bool I) { - IsInlineSpecified = I; - IsInline = I; + FunctionDeclBits.IsInlineSpecified = I; + FunctionDeclBits.IsInline = I; } /// Flag that this function is implicitly inline. - void setImplicitlyInline() { - IsInline = true; - } + void setImplicitlyInline(bool I = true) { FunctionDeclBits.IsInline = I; } /// Determine whether this function should be inlined, because it is /// either marked "inline" or "constexpr" or is a member function of a class /// that was defined in the class body. - bool isInlined() const { return IsInline; } + bool isInlined() const { return FunctionDeclBits.IsInline; } + + /// Whether this function is marked as explicit explicitly. + bool isExplicitSpecified() const { + return FunctionDeclBits.IsExplicitSpecified; + } + + /// State that this function is marked as explicit explicitly. + void setExplicitSpecified(bool ExpSpec = true) { + FunctionDeclBits.IsExplicitSpecified = ExpSpec; + } bool isInlineDefinitionExternallyVisible() const; @@ -2851,7 +2898,7 @@ public: const Type *getTypeForDecl() const { return TypeForDecl; } void setTypeForDecl(const Type *TD) { TypeForDecl = TD; } - SourceLocation getLocStart() const LLVM_READONLY { return LocStart; } + SourceLocation getBeginLoc() const LLVM_READONLY { return LocStart; } void setLocStart(SourceLocation L) { LocStart = L; } SourceRange getSourceRange() const override LLVM_READONLY { if (LocStart.isValid()) @@ -3014,64 +3061,16 @@ public: }; /// Represents the declaration of a struct/union/class/enum. -class TagDecl - : public TypeDecl, public DeclContext, public Redeclarable<TagDecl> { +class TagDecl : public TypeDecl, + public DeclContext, + public Redeclarable<TagDecl> { + // This class stores some data in DeclContext::TagDeclBits + // to save some space. Use the provided accessors to access it. public: // This is really ugly. using TagKind = TagTypeKind; private: - // FIXME: This can be packed into the bitfields in Decl. - /// The TagKind enum. - unsigned TagDeclKind : 3; - - /// True if this is a definition ("struct foo {};"), false if it is a - /// declaration ("struct foo;"). It is not considered a definition - /// until the definition has been fully processed. - unsigned IsCompleteDefinition : 1; - -protected: - /// True if this is currently being defined. - unsigned IsBeingDefined : 1; - -private: - /// True if this tag declaration is "embedded" (i.e., defined or declared - /// for the very first time) in the syntax of a declarator. - unsigned IsEmbeddedInDeclarator : 1; - - /// True if this tag is free standing, e.g. "struct foo;". - unsigned IsFreeStanding : 1; - -protected: - // These are used by (and only defined for) EnumDecl. - unsigned NumPositiveBits : 8; - unsigned NumNegativeBits : 8; - - /// True if this tag declaration is a scoped enumeration. Only - /// possible in C++11 mode. - unsigned IsScoped : 1; - - /// If this tag declaration is a scoped enum, - /// then this is true if the scoped enum was declared using the class - /// tag, false if it was declared with the struct tag. No meaning is - /// associated if this tag declaration is not a scoped enum. - unsigned IsScopedUsingClassTag : 1; - - /// True if this is an enumeration with fixed underlying type. Only - /// possible in C++11, Microsoft extensions, or Objective C mode. - unsigned IsFixed : 1; - - /// Indicates whether it is possible for declarations of this kind - /// to have an out-of-date definition. - /// - /// This option is only enabled when modules are enabled. - unsigned MayHaveOutOfDateDef : 1; - - /// Has the full definition of this type been required by a use somewhere in - /// the TU. - unsigned IsCompleteDefinitionRequired : 1; - -private: SourceRange BraceRange; // A struct representing syntactic qualifier info, @@ -3097,16 +3096,7 @@ private: protected: TagDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, TagDecl *PrevDecl, - SourceLocation StartL) - : TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), redeclarable_base(C), - TagDeclKind(TK), IsCompleteDefinition(false), IsBeingDefined(false), - IsEmbeddedInDeclarator(false), IsFreeStanding(false), - IsCompleteDefinitionRequired(false), - TypedefNameDeclOrQualifier((TypedefNameDecl *)nullptr) { - assert((DK != Enum || TK == TTK_Enum) && - "EnumDecl not matched with TTK_Enum"); - setPreviousDecl(PrevDecl); - } + SourceLocation StartL); using redeclarable_base = Redeclarable<TagDecl>; @@ -3127,6 +3117,17 @@ protected: /// This is a helper function for derived classes. void completeDefinition(); + /// True if this decl is currently being defined. + void setBeingDefined(bool V = true) { TagDeclBits.IsBeingDefined = V; } + + /// Indicates whether it is possible for declarations of this kind + /// to have an out-of-date definition. + /// + /// This option is only enabled when modules are enabled. + void setMayHaveOutOfDateDef(bool V = true) { + TagDeclBits.MayHaveOutOfDateDef = V; + } + public: friend class ASTDeclReader; friend class ASTDeclWriter; @@ -3146,7 +3147,7 @@ public: /// Return SourceLocation representing start of source /// range ignoring outer template declarations. - SourceLocation getInnerLocStart() const { return getLocStart(); } + SourceLocation getInnerLocStart() const { return getBeginLoc(); } /// Return SourceLocation representing start of source /// range taking into account any outer template declarations. @@ -3165,33 +3166,54 @@ public: } /// Return true if this decl has its body fully specified. - bool isCompleteDefinition() const { - return IsCompleteDefinition; + bool isCompleteDefinition() const { return TagDeclBits.IsCompleteDefinition; } + + /// True if this decl has its body fully specified. + void setCompleteDefinition(bool V = true) { + TagDeclBits.IsCompleteDefinition = V; } /// Return true if this complete decl is /// required to be complete for some existing use. bool isCompleteDefinitionRequired() const { - return IsCompleteDefinitionRequired; + return TagDeclBits.IsCompleteDefinitionRequired; } - /// Return true if this decl is currently being defined. - bool isBeingDefined() const { - return IsBeingDefined; + /// True if this complete decl is + /// required to be complete for some existing use. + void setCompleteDefinitionRequired(bool V = true) { + TagDeclBits.IsCompleteDefinitionRequired = V; } + /// Return true if this decl is currently being defined. + bool isBeingDefined() const { return TagDeclBits.IsBeingDefined; } + + /// True if this tag declaration is "embedded" (i.e., defined or declared + /// for the very first time) in the syntax of a declarator. bool isEmbeddedInDeclarator() const { - return IsEmbeddedInDeclarator; + return TagDeclBits.IsEmbeddedInDeclarator; } + + /// True if this tag declaration is "embedded" (i.e., defined or declared + /// for the very first time) in the syntax of a declarator. void setEmbeddedInDeclarator(bool isInDeclarator) { - IsEmbeddedInDeclarator = isInDeclarator; + TagDeclBits.IsEmbeddedInDeclarator = isInDeclarator; } - bool isFreeStanding() const { return IsFreeStanding; } + /// True if this tag is free standing, e.g. "struct foo;". + bool isFreeStanding() const { return TagDeclBits.IsFreeStanding; } + + /// True if this tag is free standing, e.g. "struct foo;". void setFreeStanding(bool isFreeStanding = true) { - IsFreeStanding = isFreeStanding; + TagDeclBits.IsFreeStanding = isFreeStanding; } + /// Indicates whether it is possible for declarations of this kind + /// to have an out-of-date definition. + /// + /// This option is only enabled when modules are enabled. + bool mayHaveOutOfDateDef() const { return TagDeclBits.MayHaveOutOfDateDef; } + /// Whether this declaration declares a type that is /// dependent, i.e., a type that somehow depends on template /// parameters. @@ -3214,21 +3236,15 @@ public: /// the struct/union/class/enum. TagDecl *getDefinition() const; - void setCompleteDefinition(bool V) { IsCompleteDefinition = V; } - - void setCompleteDefinitionRequired(bool V = true) { - IsCompleteDefinitionRequired = V; - } - StringRef getKindName() const { return TypeWithKeyword::getTagTypeKindName(getTagKind()); } TagKind getTagKind() const { - return TagKind(TagDeclKind); + return static_cast<TagKind>(TagDeclBits.TagDeclKind); } - void setTagKind(TagKind TK) { TagDeclKind = TK; } + void setTagKind(TagKind TK) { TagDeclBits.TagDeclKind = TK; } bool isStruct() const { return getTagKind() == TTK_Struct; } bool isInterface() const { return getTagKind() == TTK_Interface; } @@ -3308,6 +3324,9 @@ public: /// with a fixed underlying type, and in C we allow them to be forward-declared /// with no underlying type as an extension. class EnumDecl : public TagDecl { + // This class stores some data in DeclContext::EnumDeclBits + // to save some space. Use the provided accessors to access it. + /// This represent the integer type that the enum corresponds /// to for code generation purposes. Note that the enumerator constants may /// have a different type than this does. @@ -3336,28 +3355,50 @@ class EnumDecl : public TagDecl { MemberSpecializationInfo *SpecializationInfo = nullptr; /// Store the ODRHash after first calculation. - unsigned HasODRHash : 1; + /// The corresponding flag HasODRHash is in EnumDeclBits + /// and can be accessed with the provided accessors. unsigned ODRHash; EnumDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, EnumDecl *PrevDecl, - bool Scoped, bool ScopedUsingClassTag, bool Fixed) - : TagDecl(Enum, TTK_Enum, C, DC, IdLoc, Id, PrevDecl, StartLoc) { - assert(Scoped || !ScopedUsingClassTag); - IntegerType = (const Type *)nullptr; - NumNegativeBits = 0; - NumPositiveBits = 0; - IsScoped = Scoped; - IsScopedUsingClassTag = ScopedUsingClassTag; - IsFixed = Fixed; - HasODRHash = false; - ODRHash = 0; - } + bool Scoped, bool ScopedUsingClassTag, bool Fixed); void anchor() override; void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED, TemplateSpecializationKind TSK); + + /// Sets the width in bits required to store all the + /// non-negative enumerators of this enum. + void setNumPositiveBits(unsigned Num) { + EnumDeclBits.NumPositiveBits = Num; + assert(EnumDeclBits.NumPositiveBits == Num && "can't store this bitcount"); + } + + /// Returns the width in bits required to store all the + /// negative enumerators of this enum. (see getNumNegativeBits) + void setNumNegativeBits(unsigned Num) { EnumDeclBits.NumNegativeBits = Num; } + + /// True if this tag declaration is a scoped enumeration. Only + /// possible in C++11 mode. + void setScoped(bool Scoped = true) { EnumDeclBits.IsScoped = Scoped; } + + /// If this tag declaration is a scoped enum, + /// then this is true if the scoped enum was declared using the class + /// tag, false if it was declared with the struct tag. No meaning is + /// associated if this tag declaration is not a scoped enum. + void setScopedUsingClassTag(bool ScopedUCT = true) { + EnumDeclBits.IsScopedUsingClassTag = ScopedUCT; + } + + /// True if this is an Objective-C, C++11, or + /// Microsoft-style enumeration with a fixed underlying type. + void setFixed(bool Fixed = true) { EnumDeclBits.IsFixed = Fixed; } + + /// True if a valid hash is stored in ODRHash. + bool hasODRHash() const { return EnumDeclBits.HasODRHash; } + void setHasODRHash(bool Hash = true) { EnumDeclBits.HasODRHash = Hash; } + public: friend class ASTDeclReader; @@ -3462,13 +3503,7 @@ public: /// 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"); - } + unsigned getNumPositiveBits() const { return EnumDeclBits.NumPositiveBits; } /// Returns the width in bits required to store all the /// negative enumerators of this enum. These widths include @@ -3479,28 +3514,19 @@ public: /// -1 1111111 1 /// -10 1110110 5 /// -101 1001011 8 - unsigned getNumNegativeBits() const { - return NumNegativeBits; - } - void setNumNegativeBits(unsigned Num) { - NumNegativeBits = Num; - } + unsigned getNumNegativeBits() const { return EnumDeclBits.NumNegativeBits; } /// Returns true if this is a C++11 scoped enumeration. - bool isScoped() const { - return IsScoped; - } + bool isScoped() const { return EnumDeclBits.IsScoped; } /// Returns true if this is a C++11 scoped enumeration. bool isScopedUsingClassTag() const { - return IsScopedUsingClassTag; + return EnumDeclBits.IsScopedUsingClassTag; } /// Returns true if this is an Objective-C, C++11, or /// Microsoft-style enumeration with a fixed underlying type. - bool isFixed() const { - return IsFixed; - } + bool isFixed() const { return EnumDeclBits.IsFixed; } unsigned getODRHash(); @@ -3565,7 +3591,10 @@ public: /// union Y { int A, B; }; // Has body with members A and B (FieldDecls). /// This decl will be marked invalid if *any* members are invalid. class RecordDecl : public TagDecl { + // This class stores some data in DeclContext::RecordDeclBits + // to save some space. Use the provided accessors to access it. public: + friend class DeclContext; /// Enum that represents the different ways arguments are passed to and /// returned from function calls. This takes into account the target-specific /// and version-specific rules along with the rules determined by the @@ -3589,46 +3618,6 @@ public: APK_CanNeverPassInRegs }; -private: - friend class DeclContext; - - // FIXME: This can be packed into the bitfields in Decl. - /// 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. - unsigned HasFlexibleArrayMember : 1; - - /// Whether this is the type of an anonymous struct or union. - unsigned AnonymousStructOrUnion : 1; - - /// This is true if this struct has at least one member - /// containing an Objective-C object pointer type. - unsigned HasObjectMember : 1; - - /// This is true if struct has at least one member of - /// 'volatile' type. - unsigned HasVolatileMember : 1; - - /// 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 unsigned LoadedFieldsFromExternalStorage : 1; - - /// Basic properties of non-trivial C structs. - unsigned NonTrivialToPrimitiveDefaultInitialize : 1; - unsigned NonTrivialToPrimitiveCopy : 1; - unsigned NonTrivialToPrimitiveDestroy : 1; - - /// Indicates whether this struct is destroyed in the callee. - /// - /// Please note that MSVC won't merge adjacent bitfields if they don't have - /// the same type. - unsigned ParamDestroyedInCallee : 1; - - /// Represents the way this type is passed to a function. - unsigned ArgPassingRestrictions : 2; - protected: RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -3655,8 +3644,13 @@ public: return const_cast<RecordDecl*>(this)->getMostRecentDecl(); } - bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; } - void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; } + bool hasFlexibleArrayMember() const { + return RecordDeclBits.HasFlexibleArrayMember; + } + + void setHasFlexibleArrayMember(bool V) { + RecordDeclBits.HasFlexibleArrayMember = V; + } /// Whether this is an anonymous struct or union. To be an anonymous /// struct or union, it must have been declared without a name and @@ -3669,47 +3663,54 @@ public: /// union X { int i; float f; }; /// union { int i; float f; } obj; /// @endcode - bool isAnonymousStructOrUnion() const { return AnonymousStructOrUnion; } + bool isAnonymousStructOrUnion() const { + return RecordDeclBits.AnonymousStructOrUnion; + } + void setAnonymousStructOrUnion(bool Anon) { - AnonymousStructOrUnion = Anon; + RecordDeclBits.AnonymousStructOrUnion = Anon; } - bool hasObjectMember() const { return HasObjectMember; } - void setHasObjectMember (bool val) { HasObjectMember = val; } + bool hasObjectMember() const { return RecordDeclBits.HasObjectMember; } + void setHasObjectMember(bool val) { RecordDeclBits.HasObjectMember = val; } + + bool hasVolatileMember() const { return RecordDeclBits.HasVolatileMember; } - bool hasVolatileMember() const { return HasVolatileMember; } - void setHasVolatileMember (bool val) { HasVolatileMember = val; } + void setHasVolatileMember(bool val) { + RecordDeclBits.HasVolatileMember = val; + } bool hasLoadedFieldsFromExternalStorage() const { - return LoadedFieldsFromExternalStorage; + return RecordDeclBits.LoadedFieldsFromExternalStorage; } - void setHasLoadedFieldsFromExternalStorage(bool val) { - LoadedFieldsFromExternalStorage = val; + + void setHasLoadedFieldsFromExternalStorage(bool val) const { + RecordDeclBits.LoadedFieldsFromExternalStorage = val; } /// Functions to query basic properties of non-trivial C structs. bool isNonTrivialToPrimitiveDefaultInitialize() const { - return NonTrivialToPrimitiveDefaultInitialize; + return RecordDeclBits.NonTrivialToPrimitiveDefaultInitialize; } void setNonTrivialToPrimitiveDefaultInitialize(bool V) { - NonTrivialToPrimitiveDefaultInitialize = V; + RecordDeclBits.NonTrivialToPrimitiveDefaultInitialize = V; } bool isNonTrivialToPrimitiveCopy() const { - return NonTrivialToPrimitiveCopy; + return RecordDeclBits.NonTrivialToPrimitiveCopy; } void setNonTrivialToPrimitiveCopy(bool V) { - NonTrivialToPrimitiveCopy = V; + RecordDeclBits.NonTrivialToPrimitiveCopy = V; } bool isNonTrivialToPrimitiveDestroy() const { - return NonTrivialToPrimitiveDestroy; + return RecordDeclBits.NonTrivialToPrimitiveDestroy; } void setNonTrivialToPrimitiveDestroy(bool V) { - NonTrivialToPrimitiveDestroy = V; + RecordDeclBits.NonTrivialToPrimitiveDestroy = V; } /// Determine whether this class can be passed in registers. In C++ mode, @@ -3720,19 +3721,19 @@ public: } ArgPassingKind getArgPassingRestrictions() const { - return static_cast<ArgPassingKind>(ArgPassingRestrictions); + return static_cast<ArgPassingKind>(RecordDeclBits.ArgPassingRestrictions); } void setArgPassingRestrictions(ArgPassingKind Kind) { - ArgPassingRestrictions = static_cast<uint8_t>(Kind); + RecordDeclBits.ArgPassingRestrictions = Kind; } bool isParamDestroyedInCallee() const { - return ParamDestroyedInCallee; + return RecordDeclBits.ParamDestroyedInCallee; } void setParamDestroyedInCallee(bool V) { - ParamDestroyedInCallee = V; + RecordDeclBits.ParamDestroyedInCallee = V; } /// Determines whether this declaration represents the @@ -3855,6 +3856,8 @@ public: /// unnamed FunctionDecl. For example: /// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } class BlockDecl : public Decl, public DeclContext { + // This class stores some data in DeclContext::BlockDeclBits + // to save some space. Use the provided accessors to access it. public: /// A class which contains all the information about a particular /// captured value. @@ -3885,6 +3888,14 @@ public: /// variable. bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; } + bool isEscapingByref() const { + return getVariable()->isEscapingByref(); + } + + bool isNonEscapingByref() const { + return getVariable()->isNonEscapingByref(); + } + /// Whether this is a nested capture, i.e. the variable captured /// is not from outside the immediately enclosing function/block. bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; } @@ -3895,16 +3906,6 @@ public: }; private: - // FIXME: This can be packed into the bitfields in Decl. - bool IsVariadic : 1; - bool CapturesCXXThis : 1; - bool BlockMissingReturnType : 1; - bool IsConversionFromLambda : 1; - - /// A bit that indicates this block is passed directly to a function as a - /// non-escaping parameter. - bool DoesNotEscape : 1; - /// A new[]'d array of pointers to ParmVarDecls for the formal /// parameters of this function. This is null if a prototype or if there are /// no formals. @@ -3921,10 +3922,7 @@ private: Decl *ManglingContextDecl = nullptr; protected: - BlockDecl(DeclContext *DC, SourceLocation CaretLoc) - : Decl(Block, DC, CaretLoc), DeclContext(Block), IsVariadic(false), - CapturesCXXThis(false), BlockMissingReturnType(true), - IsConversionFromLambda(false), DoesNotEscape(false) {} + BlockDecl(DeclContext *DC, SourceLocation CaretLoc); public: static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); @@ -3932,8 +3930,8 @@ public: SourceLocation getCaretLocation() const { return getLocation(); } - bool isVariadic() const { return IsVariadic; } - void setIsVariadic(bool value) { IsVariadic = value; } + bool isVariadic() const { return BlockDeclBits.IsVariadic; } + void setIsVariadic(bool value) { BlockDeclBits.IsVariadic = value; } CompoundStmt *getCompoundBody() const { return (CompoundStmt*) Body; } Stmt *getBody() const override { return (Stmt*) Body; } @@ -3976,7 +3974,7 @@ public: /// True if this block (or its nested blocks) captures /// anything of local storage from its enclosing scopes. - bool hasCaptures() const { return NumCaptures != 0 || CapturesCXXThis; } + bool hasCaptures() const { return NumCaptures || capturesCXXThis(); } /// Returns the number of captured variables. /// Does not include an entry for 'this'. @@ -3989,15 +3987,27 @@ public: capture_const_iterator capture_begin() const { return captures().begin(); } capture_const_iterator capture_end() const { return captures().end(); } - bool capturesCXXThis() const { return CapturesCXXThis; } - bool blockMissingReturnType() const { return BlockMissingReturnType; } - void setBlockMissingReturnType(bool val) { BlockMissingReturnType = val; } + bool capturesCXXThis() const { return BlockDeclBits.CapturesCXXThis; } + void setCapturesCXXThis(bool B = true) { BlockDeclBits.CapturesCXXThis = B; } + + bool blockMissingReturnType() const { + return BlockDeclBits.BlockMissingReturnType; + } + + void setBlockMissingReturnType(bool val = true) { + BlockDeclBits.BlockMissingReturnType = val; + } - bool isConversionFromLambda() const { return IsConversionFromLambda; } - void setIsConversionFromLambda(bool val) { IsConversionFromLambda = val; } + bool isConversionFromLambda() const { + return BlockDeclBits.IsConversionFromLambda; + } + + void setIsConversionFromLambda(bool val = true) { + BlockDeclBits.IsConversionFromLambda = val; + } - bool doesNotEscape() const { return DoesNotEscape; } - void setDoesNotEscape() { DoesNotEscape = true; } + bool doesNotEscape() const { return BlockDeclBits.DoesNotEscape; } + void setDoesNotEscape(bool B = true) { BlockDeclBits.DoesNotEscape = B; } bool capturesVariable(const VarDecl *var) const; @@ -4223,16 +4233,16 @@ public: SourceLocation getRBraceLoc() const { return RBraceLoc; } void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { if (RBraceLoc.isValid()) return RBraceLoc; // No braces: get the end location of the (only) declaration in context // (if present). - return decls_empty() ? getLocation() : decls_begin()->getLocEnd(); + return decls_empty() ? getLocation() : decls_begin()->getEndLoc(); } SourceRange getSourceRange() const override LLVM_READONLY { - return SourceRange(getLocation(), getLocEnd()); + return SourceRange(getLocation(), getEndLoc()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index d6b89d971d94..8405a43fa098 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -16,6 +16,7 @@ #include "clang/AST/AttrIterator.h" #include "clang/AST/DeclarationName.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" @@ -406,11 +407,11 @@ public: return SourceRange(getLocation(), getLocation()); } - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getBeginLoc() const LLVM_READONLY { return getSourceRange().getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { return getSourceRange().getEnd(); } @@ -481,13 +482,7 @@ public: const AttrVec &getAttrs() const; void dropAttrs(); - - void addAttr(Attr *A) { - if (hasAttrs()) - getAttrs().push_back(A); - else - setAttrs(AttrVec(1, A)); - } + void addAttr(Attr *A); using attr_iterator = AttrVec::const_iterator; using attr_range = llvm::iterator_range<attr_iterator>; @@ -1070,11 +1065,11 @@ public: unsigned OldNS = IdentifierNamespace; assert((OldNS & (IDNS_Tag | IDNS_Ordinary | IDNS_TagFriend | IDNS_OrdinaryFriend | - IDNS_LocalExtern)) && + IDNS_LocalExtern | IDNS_NonMemberOperator)) && "namespace includes neither ordinary nor tag"); assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | IDNS_TagFriend | IDNS_OrdinaryFriend | - IDNS_LocalExtern)) && + IDNS_LocalExtern | IDNS_NonMemberOperator)) && "namespace includes other than ordinary or tag"); Decl *Prev = getPreviousDecl(); @@ -1087,7 +1082,8 @@ public: IdentifierNamespace |= IDNS_Tag | IDNS_Type; } - if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) { + if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | + IDNS_LocalExtern | IDNS_NonMemberOperator)) { IdentifierNamespace |= IDNS_OrdinaryFriend; if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)) @@ -1141,6 +1137,9 @@ public: void dump(raw_ostream &Out, bool Deserialize = false) const; + /// \return Unique reproducible object identifier + int64_t getID() const; + /// Looks through the Decl's underlying type to extract a FunctionType /// when possible. Will return null if the type underlying the Decl does not /// have a FunctionType. @@ -1214,7 +1213,6 @@ public: value_type SingleElement; public: - iterator() = default; explicit iterator(pointer Pos, value_type Single = nullptr) : IteratorBase(Pos), SingleElement(Single) {} @@ -1250,47 +1248,424 @@ public: /// that directly derive from DeclContext are mentioned, not their subclasses): /// /// TranslationUnitDecl +/// ExternCContext /// NamespaceDecl -/// FunctionDecl /// TagDecl +/// OMPDeclareReductionDecl +/// FunctionDecl /// ObjCMethodDecl /// ObjCContainerDecl /// LinkageSpecDecl /// ExportDecl /// BlockDecl -/// OMPDeclareReductionDecl +/// CapturedDecl class DeclContext { - /// DeclKind - This indicates which class this is. - unsigned DeclKind : 8; + /// For makeDeclVisibleInContextImpl + friend class ASTDeclReader; + /// For reconcileExternalVisibleStorage, CreateStoredDeclsMap, + /// hasNeedToReconcileExternalVisibleStorage + friend class ExternalASTSource; + /// For CreateStoredDeclsMap + friend class DependentDiagnostic; + /// For hasNeedToReconcileExternalVisibleStorage, + /// hasLazyLocalLexicalLookups, hasLazyExternalLexicalLookups + friend class ASTWriter; - /// Whether this declaration context also has some external - /// storage that contains additional declarations that are lexically - /// part of this context. - mutable bool ExternalLexicalStorage : 1; + // We use uint64_t in the bit-fields below since some bit-fields + // cross the unsigned boundary and this breaks the packing. - /// Whether this declaration context also has some external - /// storage that contains additional declarations that are visible - /// in this context. - mutable bool ExternalVisibleStorage : 1; + /// Stores the bits used by DeclContext. + /// If modified NumDeclContextBit, the ctor of DeclContext and the accessor + /// methods in DeclContext should be updated appropriately. + class DeclContextBitfields { + friend class DeclContext; + /// DeclKind - This indicates which class this is. + uint64_t DeclKind : 7; - /// Whether this declaration context has had external visible - /// storage added since the last lookup. In this case, \c LookupPtr's - /// invariant may not hold and needs to be fixed before we perform - /// another lookup. - mutable bool NeedToReconcileExternalVisibleStorage : 1; + /// Whether this declaration context also has some external + /// storage that contains additional declarations that are lexically + /// part of this context. + mutable uint64_t ExternalLexicalStorage : 1; - /// If \c true, this context may have local lexical declarations - /// that are missing from the lookup table. - mutable bool HasLazyLocalLexicalLookups : 1; + /// Whether this declaration context also has some external + /// storage that contains additional declarations that are visible + /// in this context. + mutable uint64_t ExternalVisibleStorage : 1; - /// If \c true, the external source may have lexical declarations - /// that are missing from the lookup table. - mutable bool HasLazyExternalLexicalLookups : 1; + /// Whether this declaration context has had externally visible + /// storage added since the last lookup. In this case, \c LookupPtr's + /// invariant may not hold and needs to be fixed before we perform + /// another lookup. + mutable uint64_t NeedToReconcileExternalVisibleStorage : 1; + + /// If \c true, this context may have local lexical declarations + /// that are missing from the lookup table. + mutable uint64_t HasLazyLocalLexicalLookups : 1; + + /// If \c true, the external source may have lexical declarations + /// that are missing from the lookup table. + mutable uint64_t HasLazyExternalLexicalLookups : 1; + + /// If \c true, lookups should only return identifier from + /// DeclContext scope (for example TranslationUnit). Used in + /// LookupQualifiedName() + mutable uint64_t UseQualifiedLookup : 1; + }; + + /// Number of bits in DeclContextBitfields. + enum { NumDeclContextBits = 13 }; + + /// Stores the bits used by TagDecl. + /// If modified NumTagDeclBits and the accessor + /// methods in TagDecl should be updated appropriately. + class TagDeclBitfields { + friend class TagDecl; + /// For the bits in DeclContextBitfields + uint64_t : NumDeclContextBits; + + /// The TagKind enum. + uint64_t TagDeclKind : 3; + + /// True if this is a definition ("struct foo {};"), false if it is a + /// declaration ("struct foo;"). It is not considered a definition + /// until the definition has been fully processed. + uint64_t IsCompleteDefinition : 1; + + /// True if this is currently being defined. + uint64_t IsBeingDefined : 1; + + /// True if this tag declaration is "embedded" (i.e., defined or declared + /// for the very first time) in the syntax of a declarator. + uint64_t IsEmbeddedInDeclarator : 1; + + /// True if this tag is free standing, e.g. "struct foo;". + uint64_t IsFreeStanding : 1; + + /// Indicates whether it is possible for declarations of this kind + /// to have an out-of-date definition. + /// + /// This option is only enabled when modules are enabled. + uint64_t MayHaveOutOfDateDef : 1; + + /// Has the full definition of this type been required by a use somewhere in + /// the TU. + uint64_t IsCompleteDefinitionRequired : 1; + }; + + /// Number of non-inherited bits in TagDeclBitfields. + enum { NumTagDeclBits = 9 }; + + /// Stores the bits used by EnumDecl. + /// If modified NumEnumDeclBit and the accessor + /// methods in EnumDecl should be updated appropriately. + class EnumDeclBitfields { + friend class EnumDecl; + /// For the bits in DeclContextBitfields. + uint64_t : NumDeclContextBits; + /// For the bits in TagDeclBitfields. + uint64_t : NumTagDeclBits; + + /// Width in bits required to store all the non-negative + /// enumerators of this enum. + uint64_t NumPositiveBits : 8; + + /// Width in bits required to store all the negative + /// enumerators of this enum. + uint64_t NumNegativeBits : 8; + + /// True if this tag declaration is a scoped enumeration. Only + /// possible in C++11 mode. + uint64_t IsScoped : 1; + + /// 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. + uint64_t IsScopedUsingClassTag : 1; + + /// True if this is an enumeration with fixed underlying type. Only + /// possible in C++11, Microsoft extensions, or Objective C mode. + uint64_t IsFixed : 1; + + /// True if a valid hash is stored in ODRHash. + uint64_t HasODRHash : 1; + }; + + /// Number of non-inherited bits in EnumDeclBitfields. + enum { NumEnumDeclBits = 20 }; + + /// Stores the bits used by RecordDecl. + /// If modified NumRecordDeclBits and the accessor + /// methods in RecordDecl should be updated appropriately. + class RecordDeclBitfields { + friend class RecordDecl; + /// For the bits in DeclContextBitfields. + uint64_t : NumDeclContextBits; + /// For the bits in TagDeclBitfields. + uint64_t : NumTagDeclBits; + + /// 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. + uint64_t HasFlexibleArrayMember : 1; + + /// Whether this is the type of an anonymous struct or union. + uint64_t AnonymousStructOrUnion : 1; + + /// This is true if this struct has at least one member + /// containing an Objective-C object pointer type. + uint64_t HasObjectMember : 1; + + /// This is true if struct has at least one member of + /// 'volatile' type. + uint64_t HasVolatileMember : 1; + + /// 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 uint64_t LoadedFieldsFromExternalStorage : 1; + + /// Basic properties of non-trivial C structs. + uint64_t NonTrivialToPrimitiveDefaultInitialize : 1; + uint64_t NonTrivialToPrimitiveCopy : 1; + uint64_t NonTrivialToPrimitiveDestroy : 1; + + /// Indicates whether this struct is destroyed in the callee. + uint64_t ParamDestroyedInCallee : 1; + + /// Represents the way this type is passed to a function. + uint64_t ArgPassingRestrictions : 2; + }; + + /// Number of non-inherited bits in RecordDeclBitfields. + enum { NumRecordDeclBits = 11 }; + + /// Stores the bits used by OMPDeclareReductionDecl. + /// If modified NumOMPDeclareReductionDeclBits and the accessor + /// methods in OMPDeclareReductionDecl should be updated appropriately. + class OMPDeclareReductionDeclBitfields { + friend class OMPDeclareReductionDecl; + /// For the bits in DeclContextBitfields + uint64_t : NumDeclContextBits; + + /// Kind of initializer, + /// function call or omp_priv<init_expr> initializtion. + uint64_t InitializerKind : 2; + }; + + /// Number of non-inherited bits in OMPDeclareReductionDeclBitfields. + enum { NumOMPDeclareReductionDeclBits = 2 }; + + /// Stores the bits used by FunctionDecl. + /// If modified NumFunctionDeclBits and the accessor + /// methods in FunctionDecl and CXXDeductionGuideDecl + /// (for IsCopyDeductionCandidate) should be updated appropriately. + class FunctionDeclBitfields { + friend class FunctionDecl; + /// For IsCopyDeductionCandidate + friend class CXXDeductionGuideDecl; + /// For the bits in DeclContextBitfields. + uint64_t : NumDeclContextBits; + + uint64_t SClass : 3; + uint64_t IsInline : 1; + uint64_t IsInlineSpecified : 1; + + /// This is shared by CXXConstructorDecl, + /// CXXConversionDecl, and CXXDeductionGuideDecl. + uint64_t IsExplicitSpecified : 1; + + uint64_t IsVirtualAsWritten : 1; + uint64_t IsPure : 1; + uint64_t HasInheritedPrototype : 1; + uint64_t HasWrittenPrototype : 1; + uint64_t IsDeleted : 1; + /// Used by CXXMethodDecl + uint64_t IsTrivial : 1; + + /// This flag indicates whether this function is trivial for the purpose of + /// calls. This is meaningful only when this function is a copy/move + /// constructor or a destructor. + uint64_t IsTrivialForCall : 1; + + /// Used by CXXMethodDecl + uint64_t IsDefaulted : 1; + /// Used by CXXMethodDecl + uint64_t IsExplicitlyDefaulted : 1; + uint64_t HasImplicitReturnZero : 1; + uint64_t IsLateTemplateParsed : 1; + uint64_t IsConstexpr : 1; + uint64_t InstantiationIsPending : 1; + + /// Indicates if the function uses __try. + uint64_t UsesSEHTry : 1; + + /// Indicates if the function was a definition + /// but its body was skipped. + uint64_t HasSkippedBody : 1; + + /// Indicates if the function declaration will + /// have a body, once we're done parsing it. + uint64_t WillHaveBody : 1; + + /// Indicates that this function is a multiversioned + /// function using attribute 'target'. + uint64_t IsMultiVersion : 1; + + /// [C++17] Only used by CXXDeductionGuideDecl. Indicates that + /// the Deduction Guide is the implicitly generated 'copy + /// deduction candidate' (is used during overload resolution). + uint64_t IsCopyDeductionCandidate : 1; + + /// Store the ODRHash after first calculation. + uint64_t HasODRHash : 1; + }; + + /// Number of non-inherited bits in FunctionDeclBitfields. + enum { NumFunctionDeclBits = 25 }; - /// If \c true, lookups should only return identifier from - /// DeclContext scope (for example TranslationUnit). Used in - /// LookupQualifiedName() - mutable bool UseQualifiedLookup : 1; + /// Stores the bits used by CXXConstructorDecl. If modified + /// NumCXXConstructorDeclBits and the accessor + /// methods in CXXConstructorDecl should be updated appropriately. + class CXXConstructorDeclBitfields { + friend class CXXConstructorDecl; + /// For the bits in DeclContextBitfields. + uint64_t : NumDeclContextBits; + /// For the bits in FunctionDeclBitfields. + uint64_t : NumFunctionDeclBits; + + /// 25 bits to fit in the remaining availible space. + /// Note that this makes CXXConstructorDeclBitfields take + /// exactly 64 bits and thus the width of NumCtorInitializers + /// will need to be shrunk if some bit is added to NumDeclContextBitfields, + /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields. + uint64_t NumCtorInitializers : 25; + uint64_t IsInheritingConstructor : 1; + }; + + /// Number of non-inherited bits in CXXConstructorDeclBitfields. + enum { NumCXXConstructorDeclBits = 26 }; + + /// Stores the bits used by ObjCMethodDecl. + /// If modified NumObjCMethodDeclBits and the accessor + /// methods in ObjCMethodDecl should be updated appropriately. + class ObjCMethodDeclBitfields { + friend class ObjCMethodDecl; + + /// For the bits in DeclContextBitfields. + uint64_t : NumDeclContextBits; + + /// The conventional meaning of this method; an ObjCMethodFamily. + /// This is not serialized; instead, it is computed on demand and + /// cached. + mutable uint64_t Family : ObjCMethodFamilyBitWidth; + + /// instance (true) or class (false) method. + uint64_t IsInstance : 1; + uint64_t IsVariadic : 1; + + /// True if this method is the getter or setter for an explicit property. + uint64_t IsPropertyAccessor : 1; + + /// Method has a definition. + uint64_t IsDefined : 1; + + /// Method redeclaration in the same interface. + uint64_t IsRedeclaration : 1; + + /// Is redeclared in the same interface. + mutable uint64_t HasRedeclaration : 1; + + /// \@required/\@optional + uint64_t DeclImplementation : 2; + + /// in, inout, etc. + uint64_t objcDeclQualifier : 7; + + /// Indicates whether this method has a related result type. + uint64_t RelatedResultType : 1; + + /// Whether the locations of the selector identifiers are in a + /// "standard" position, a enum SelectorLocationsKind. + uint64_t SelLocsKind : 2; + + /// Whether this method overrides any other in the class hierarchy. + /// + /// A method is said to override any method in the class's + /// base classes, its protocols, or its categories' protocols, that has + /// the same selector and is of the same kind (class or instance). + /// A method in an implementation is not considered as overriding the same + /// method in the interface or its categories. + uint64_t IsOverriding : 1; + + /// Indicates if the method was a definition but its body was skipped. + uint64_t HasSkippedBody : 1; + }; + + /// Number of non-inherited bits in ObjCMethodDeclBitfields. + enum { NumObjCMethodDeclBits = 24 }; + + /// Stores the bits used by ObjCContainerDecl. + /// If modified NumObjCContainerDeclBits and the accessor + /// methods in ObjCContainerDecl should be updated appropriately. + class ObjCContainerDeclBitfields { + friend class ObjCContainerDecl; + /// For the bits in DeclContextBitfields + uint32_t : NumDeclContextBits; + + // Not a bitfield but this saves space. + // Note that ObjCContainerDeclBitfields is full. + SourceLocation AtStart; + }; + + /// Number of non-inherited bits in ObjCContainerDeclBitfields. + /// Note that here we rely on the fact that SourceLocation is 32 bits + /// wide. We check this with the static_assert in the ctor of DeclContext. + enum { NumObjCContainerDeclBits = 64 - NumDeclContextBits }; + + /// Stores the bits used by LinkageSpecDecl. + /// If modified NumLinkageSpecDeclBits and the accessor + /// methods in LinkageSpecDecl should be updated appropriately. + class LinkageSpecDeclBitfields { + friend class LinkageSpecDecl; + /// For the bits in DeclContextBitfields. + uint64_t : NumDeclContextBits; + + /// The language for this linkage specification with values + /// in the enum LinkageSpecDecl::LanguageIDs. + uint64_t Language : 3; + + /// True if this linkage spec has braces. + /// This is needed so that hasBraces() returns the correct result while the + /// linkage spec body is being parsed. Once RBraceLoc has been set this is + /// not used, so it doesn't need to be serialized. + uint64_t HasBraces : 1; + }; + + /// Number of non-inherited bits in LinkageSpecDeclBitfields. + enum { NumLinkageSpecDeclBits = 4 }; + + /// Stores the bits used by BlockDecl. + /// If modified NumBlockDeclBits and the accessor + /// methods in BlockDecl should be updated appropriately. + class BlockDeclBitfields { + friend class BlockDecl; + /// For the bits in DeclContextBitfields. + uint64_t : NumDeclContextBits; + + uint64_t IsVariadic : 1; + uint64_t CapturesCXXThis : 1; + uint64_t BlockMissingReturnType : 1; + uint64_t IsConversionFromLambda : 1; + + /// A bit that indicates this block is passed directly to a function as a + /// non-escaping parameter. + uint64_t DoesNotEscape : 1; + }; + + /// Number of non-inherited bits in BlockDeclBitfields. + enum { NumBlockDeclBits = 5 }; /// Pointer to the data structure used to lookup declarations /// within this context (or a DependentStoredDeclsMap if this is a @@ -1301,9 +1676,50 @@ class DeclContext { mutable StoredDeclsMap *LookupPtr = nullptr; protected: - friend class ASTDeclReader; - friend class ASTWriter; - friend class ExternalASTSource; + /// This anonymous union stores the bits belonging to DeclContext and classes + /// deriving from it. The goal is to use otherwise wasted + /// space in DeclContext to store data belonging to derived classes. + /// The space saved is especially significient when pointers are aligned + /// to 8 bytes. In this case due to alignment requirements we have a + /// little less than 8 bytes free in DeclContext which we can use. + /// We check that none of the classes in this union is larger than + /// 8 bytes with static_asserts in the ctor of DeclContext. + union { + DeclContextBitfields DeclContextBits; + TagDeclBitfields TagDeclBits; + EnumDeclBitfields EnumDeclBits; + RecordDeclBitfields RecordDeclBits; + OMPDeclareReductionDeclBitfields OMPDeclareReductionDeclBits; + FunctionDeclBitfields FunctionDeclBits; + CXXConstructorDeclBitfields CXXConstructorDeclBits; + ObjCMethodDeclBitfields ObjCMethodDeclBits; + ObjCContainerDeclBitfields ObjCContainerDeclBits; + LinkageSpecDeclBitfields LinkageSpecDeclBits; + BlockDeclBitfields BlockDeclBits; + + static_assert(sizeof(DeclContextBitfields) <= 8, + "DeclContextBitfields is larger than 8 bytes!"); + static_assert(sizeof(TagDeclBitfields) <= 8, + "TagDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(EnumDeclBitfields) <= 8, + "EnumDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(RecordDeclBitfields) <= 8, + "RecordDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(OMPDeclareReductionDeclBitfields) <= 8, + "OMPDeclareReductionDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(FunctionDeclBitfields) <= 8, + "FunctionDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(CXXConstructorDeclBitfields) <= 8, + "CXXConstructorDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(ObjCMethodDeclBitfields) <= 8, + "ObjCMethodDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(ObjCContainerDeclBitfields) <= 8, + "ObjCContainerDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(LinkageSpecDeclBitfields) <= 8, + "LinkageSpecDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(BlockDeclBitfields) <= 8, + "BlockDeclBitfields is larger than 8 bytes!"); + }; /// FirstDecl - The first declaration stored within this declaration /// context. @@ -1321,18 +1737,13 @@ protected: static std::pair<Decl *, Decl *> BuildDeclChain(ArrayRef<Decl*> Decls, bool FieldsAlreadyLoaded); - DeclContext(Decl::Kind K) - : DeclKind(K), ExternalLexicalStorage(false), - ExternalVisibleStorage(false), - NeedToReconcileExternalVisibleStorage(false), - HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false), - UseQualifiedLookup(false) {} + DeclContext(Decl::Kind K); public: ~DeclContext(); Decl::Kind getDeclKind() const { - return static_cast<Decl::Kind>(DeclKind); + return static_cast<Decl::Kind>(DeclContextBits.DeclKind); } const char *getDeclKindName() const; @@ -1371,54 +1782,54 @@ public: return cast<Decl>(this)->getASTContext(); } - bool isClosure() const { - return DeclKind == Decl::Block; - } + bool isClosure() const { return getDeclKind() == Decl::Block; } bool isObjCContainer() const { - switch (DeclKind) { - case Decl::ObjCCategory: - case Decl::ObjCCategoryImpl: - case Decl::ObjCImplementation: - case Decl::ObjCInterface: - case Decl::ObjCProtocol: - return true; + switch (getDeclKind()) { + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::ObjCInterface: + case Decl::ObjCProtocol: + return true; + default: + return false; } - return false; } bool isFunctionOrMethod() const { - switch (DeclKind) { + switch (getDeclKind()) { case Decl::Block: case Decl::Captured: case Decl::ObjCMethod: return true; default: - return DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction; + return getDeclKind() >= Decl::firstFunction && + getDeclKind() <= Decl::lastFunction; } } /// Test whether the context supports looking up names. bool isLookupContext() const { - return !isFunctionOrMethod() && DeclKind != Decl::LinkageSpec && - DeclKind != Decl::Export; + return !isFunctionOrMethod() && getDeclKind() != Decl::LinkageSpec && + getDeclKind() != Decl::Export; } bool isFileContext() const { - return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace; + return getDeclKind() == Decl::TranslationUnit || + getDeclKind() == Decl::Namespace; } bool isTranslationUnit() const { - return DeclKind == Decl::TranslationUnit; + return getDeclKind() == Decl::TranslationUnit; } bool isRecord() const { - return DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord; + return getDeclKind() >= Decl::firstRecord && + getDeclKind() <= Decl::lastRecord; } - bool isNamespace() const { - return DeclKind == Decl::Namespace; - } + bool isNamespace() const { return getDeclKind() == Decl::Namespace; } bool isStdNamespace() const; @@ -1886,7 +2297,7 @@ public: void setMustBuildLookupTable() { assert(this == getPrimaryContext() && "should only be called on primary context"); - HasLazyExternalLexicalLookups = true; + DeclContextBits.HasLazyExternalLexicalLookups = true; } /// Retrieve the internal representation of the lookup structure. @@ -1898,24 +2309,28 @@ public: /// Whether this DeclContext has external storage containing /// additional declarations that are lexically in this context. - bool hasExternalLexicalStorage() const { return ExternalLexicalStorage; } + bool hasExternalLexicalStorage() const { + return DeclContextBits.ExternalLexicalStorage; + } /// State whether this DeclContext has external storage for /// declarations lexically in this context. - void setHasExternalLexicalStorage(bool ES = true) { - ExternalLexicalStorage = ES; + void setHasExternalLexicalStorage(bool ES = true) const { + DeclContextBits.ExternalLexicalStorage = ES; } /// Whether this DeclContext has external storage containing /// additional declarations that are visible in this context. - bool hasExternalVisibleStorage() const { return ExternalVisibleStorage; } + bool hasExternalVisibleStorage() const { + return DeclContextBits.ExternalVisibleStorage; + } /// State whether this DeclContext has external storage for /// declarations visible in this context. - void setHasExternalVisibleStorage(bool ES = true) { - ExternalVisibleStorage = ES; + void setHasExternalVisibleStorage(bool ES = true) const { + DeclContextBits.ExternalVisibleStorage = ES; if (ES && LookupPtr) - NeedToReconcileExternalVisibleStorage = true; + DeclContextBits.NeedToReconcileExternalVisibleStorage = true; } /// Determine whether the given declaration is stored in the list of @@ -1925,14 +2340,14 @@ public: D == LastDecl); } - bool setUseQualifiedLookup(bool use = true) { - bool old_value = UseQualifiedLookup; - UseQualifiedLookup = use; + bool setUseQualifiedLookup(bool use = true) const { + bool old_value = DeclContextBits.UseQualifiedLookup; + DeclContextBits.UseQualifiedLookup = use; return old_value; } bool shouldUseQualifiedLookup() const { - return UseQualifiedLookup; + return DeclContextBits.UseQualifiedLookup; } static bool classof(const Decl *D); @@ -1944,7 +2359,45 @@ public: bool Deserialize = false) const; private: - friend class DependentDiagnostic; + /// Whether this declaration context has had externally visible + /// storage added since the last lookup. In this case, \c LookupPtr's + /// invariant may not hold and needs to be fixed before we perform + /// another lookup. + bool hasNeedToReconcileExternalVisibleStorage() const { + return DeclContextBits.NeedToReconcileExternalVisibleStorage; + } + + /// State that this declaration context has had externally visible + /// storage added since the last lookup. In this case, \c LookupPtr's + /// invariant may not hold and needs to be fixed before we perform + /// another lookup. + void setNeedToReconcileExternalVisibleStorage(bool Need = true) const { + DeclContextBits.NeedToReconcileExternalVisibleStorage = Need; + } + + /// If \c true, this context may have local lexical declarations + /// that are missing from the lookup table. + bool hasLazyLocalLexicalLookups() const { + return DeclContextBits.HasLazyLocalLexicalLookups; + } + + /// If \c true, this context may have local lexical declarations + /// that are missing from the lookup table. + void setHasLazyLocalLexicalLookups(bool HasLLLL = true) const { + DeclContextBits.HasLazyLocalLexicalLookups = HasLLLL; + } + + /// If \c true, the external source may have lexical declarations + /// that are missing from the lookup table. + bool hasLazyExternalLexicalLookups() const { + return DeclContextBits.HasLazyExternalLexicalLookups; + } + + /// If \c true, the external source may have lexical declarations + /// that are missing from the lookup table. + void setHasLazyExternalLexicalLookups(bool HasLELL = true) const { + DeclContextBits.HasLazyExternalLexicalLookups = HasLELL; + } void reconcileExternalVisibleStorage() const; bool LoadLexicalDeclsFromExternalStorage() const; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 4353f66a34e4..d3357c245d86 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -233,12 +233,12 @@ public: /// Retrieves the source range that contains the entire base specifier. SourceRange getSourceRange() const LLVM_READONLY { return Range; } - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } /// Get the location at which the base class type was written. SourceLocation getBaseTypeLoc() const LLVM_READONLY { - return BaseTypeInfo->getTypeLoc().getLocStart(); + return BaseTypeInfo->getTypeLoc().getBeginLoc(); } /// Determines whether the base class is a virtual base class (or not). @@ -974,10 +974,7 @@ public: bool needsImplicitDefaultConstructor() const { return !data().UserDeclaredConstructor && !(data().DeclaredSpecialMembers & SMF_DefaultConstructor) && - // C++14 [expr.prim.lambda]p20: - // The closure type associated with a lambda-expression has no - // default constructor. - !isLambda(); + (!isLambda() || lambdaIsDefaultConstructibleAndAssignable()); } /// Determine whether this class has any user-declared constructors. @@ -1167,10 +1164,7 @@ public: !hasUserDeclaredCopyAssignment() && !hasUserDeclaredMoveConstructor() && !hasUserDeclaredDestructor() && - // C++1z [expr.prim.lambda]p21: "the closure type has a deleted copy - // assignment operator". The intent is that this counts as a user - // declared copy assignment, but we do not model it that way. - !isLambda(); + (!isLambda() || lambdaIsDefaultConstructibleAndAssignable()); } /// Determine whether we need to eagerly declare a move assignment @@ -1210,6 +1204,10 @@ public: /// a template). bool isGenericLambda() const; + /// Determine whether this lambda should have an implicit default constructor + /// and copy and move assignment operators. + bool lambdaIsDefaultConstructibleAndAssignable() const; + /// Retrieve the lambda call operator of the closure type /// if this is a closure type. CXXMethodDecl *getLambdaCallOperator() const; @@ -1543,7 +1541,7 @@ public: /// /// C++11 [class]p6: /// "A trivial class is a class that has a trivial default constructor and - /// is trivially copiable." + /// is trivially copyable." bool isTrivial() const { return isTriviallyCopyable() && hasTrivialDefaultConstructor(); } @@ -1999,7 +1997,8 @@ private: SC_None, false, false) { if (EndLocation.isValid()) setRangeEnd(EndLocation); - IsExplicitSpecified = IsExplicit; + setExplicitSpecified(IsExplicit); + setIsCopyDeductionCandidate(false); } public: @@ -2015,21 +2014,20 @@ public: static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID); /// Whether this deduction guide is explicit. - bool isExplicit() const { return IsExplicitSpecified; } - - /// Whether this deduction guide was declared with the 'explicit' specifier. - bool isExplicitSpecified() const { return IsExplicitSpecified; } + bool isExplicit() const { return isExplicitSpecified(); } /// Get the template for which this guide performs deduction. TemplateDecl *getDeducedTemplate() const { return getDeclName().getCXXDeductionGuideTemplate(); } - void setIsCopyDeductionCandidate() { - IsCopyDeductionCandidate = true; + void setIsCopyDeductionCandidate(bool isCDC = true) { + FunctionDeclBits.IsCopyDeductionCandidate = isCDC; } - bool isCopyDeductionCandidate() const { return IsCopyDeductionCandidate; } + bool isCopyDeductionCandidate() const { + return FunctionDeclBits.IsCopyDeductionCandidate; + } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -2109,10 +2107,15 @@ public: Base, IsAppleKext); } - /// Determine whether this is a usual deallocation function - /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded - /// delete or delete[] operator with a particular signature. - bool isUsualDeallocationFunction() const; + /// Determine whether this is a usual deallocation function (C++ + /// [basic.stc.dynamic.deallocation]p2), which is an overloaded delete or + /// delete[] operator with a particular signature. Populates \p PreventedBy + /// with the declarations of the functions of the same kind if they were the + /// reason for this function returning false. This is used by + /// Sema::isUsualDeallocationFunction to reconsider the answer based on the + /// context. + bool isUsualDeallocationFunction( + SmallVectorImpl<const FunctionDecl *> &PreventedBy) const; /// Determine whether this is a copy-assignment operator, regardless /// of whether it was declared implicitly or explicitly. @@ -2177,9 +2180,12 @@ public: /// that for the call operator of a lambda closure type, this returns the /// desugared 'this' type (a pointer to the closure type), not the captured /// 'this' type. - QualType getThisType(ASTContext &C) const; + QualType getThisType() const; + + static QualType getThisType(const FunctionProtoType *FPT, + const CXXRecordDecl *Decl); - unsigned getTypeQualifiers() const { + Qualifiers getTypeQualifiers() const { return getType()->getAs<FunctionProtoType>()->getTypeQuals(); } @@ -2312,6 +2318,9 @@ public: CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, SourceLocation L, Expr *Init, SourceLocation R); + /// \return Unique reproducible object identifier. + int64_t getID(const ASTContext &Context) const; + /// Determine whether this initializer is initializing a base class. bool isBaseInitializer() const { return Initializee.is<TypeSourceInfo*>() && !IsDelegating; @@ -2475,31 +2484,20 @@ public: class CXXConstructorDecl final : public CXXMethodDecl, private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor> { + // This class stores some data in DeclContext::CXXConstructorDeclBits + // to save some space. Use the provided accessors to access it. + /// \name Support for base and member initializers. /// \{ /// The arguments used to initialize the base or member. LazyCXXCtorInitializersPtr CtorInitializers; - unsigned NumCtorInitializers : 31; - /// \} - - /// Whether this constructor declaration is an implicitly-declared - /// inheriting constructor. - unsigned IsInheritingConstructor : 1; CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared, bool isConstexpr, - InheritedConstructor Inherited) - : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, isConstexpr, SourceLocation()), - NumCtorInitializers(0), IsInheritingConstructor((bool)Inherited) { - setImplicit(isImplicitlyDeclared); - if (Inherited) - *getTrailingObjects<InheritedConstructor>() = Inherited; - IsExplicitSpecified = isExplicitSpecified; - } + InheritedConstructor Inherited); void anchor() override; @@ -2542,12 +2540,12 @@ public: /// Retrieve an iterator past the last initializer. init_iterator init_end() { - return init_begin() + NumCtorInitializers; + return init_begin() + getNumCtorInitializers(); } /// Retrieve an iterator past the last initializer. init_const_iterator init_end() const { - return init_begin() + NumCtorInitializers; + return init_begin() + getNumCtorInitializers(); } using init_reverse_iterator = std::reverse_iterator<init_iterator>; @@ -2571,20 +2569,22 @@ public: /// Determine the number of arguments used to initialize the member /// or base. unsigned getNumCtorInitializers() const { - return NumCtorInitializers; + return CXXConstructorDeclBits.NumCtorInitializers; } void setNumCtorInitializers(unsigned numCtorInitializers) { - NumCtorInitializers = numCtorInitializers; + CXXConstructorDeclBits.NumCtorInitializers = numCtorInitializers; + // This assert added because NumCtorInitializers is stored + // in CXXConstructorDeclBits as a bitfield and its width has + // been shrunk from 32 bits to fit into CXXConstructorDeclBitfields. + assert(CXXConstructorDeclBits.NumCtorInitializers == + numCtorInitializers && "NumCtorInitializers overflow!"); } void setCtorInitializers(CXXCtorInitializer **Initializers) { CtorInitializers = Initializers; } - /// Whether this function is marked as explicit explicitly. - bool isExplicitSpecified() const { return IsExplicitSpecified; } - /// Whether this function is explicit. bool isExplicit() const { return getCanonicalDecl()->isExplicitSpecified(); @@ -2665,12 +2665,20 @@ public: /// Determine whether this is an implicit constructor synthesized to /// model a call to a constructor inherited from a base class. - bool isInheritingConstructor() const { return IsInheritingConstructor; } + bool isInheritingConstructor() const { + return CXXConstructorDeclBits.IsInheritingConstructor; + } + + /// State that this is an implicit constructor synthesized to + /// model a call to a constructor inherited from a base class. + void setInheritingConstructor(bool isIC = true) { + CXXConstructorDeclBits.IsInheritingConstructor = isIC; + } /// Get the constructor that this inheriting constructor is based on. InheritedConstructor getInheritedConstructor() const { - return IsInheritingConstructor ? *getTrailingObjects<InheritedConstructor>() - : InheritedConstructor(); + return isInheritingConstructor() ? + *getTrailingObjects<InheritedConstructor>() : InheritedConstructor(); } CXXConstructorDecl *getCanonicalDecl() override { @@ -2765,7 +2773,7 @@ class CXXConversionDecl : public CXXMethodDecl { SourceLocation EndLocation) : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo, SC_None, isInline, isConstexpr, EndLocation) { - IsExplicitSpecified = isExplicitSpecified; + setExplicitSpecified(isExplicitSpecified); } void anchor() override; @@ -2783,9 +2791,6 @@ public: SourceLocation EndLocation); static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID); - /// Whether this function is marked as explicit explicitly. - bool isExplicitSpecified() const { return IsExplicitSpecified; } - /// Whether this function is explicit. bool isExplicit() const { return getCanonicalDecl()->isExplicitSpecified(); @@ -2820,7 +2825,8 @@ public: /// \endcode class LinkageSpecDecl : public Decl, public DeclContext { virtual void anchor(); - + // This class stores some data in DeclContext::LinkageSpecDeclBits to save + // some space. Use the provided accessors to access it. public: /// Represents the language in a linkage specification. /// @@ -2834,16 +2840,6 @@ public: }; private: - /// The language for this linkage specification. - unsigned Language : 3; - - /// True if this linkage spec has braces. - /// - /// This is needed so that hasBraces() returns the correct result while the - /// linkage spec body is being parsed. Once RBraceLoc has been set this is - /// not used, so it doesn't need to be serialized. - unsigned HasBraces : 1; - /// The source location for the extern keyword. SourceLocation ExternLoc; @@ -2851,10 +2847,7 @@ private: SourceLocation RBraceLoc; LinkageSpecDecl(DeclContext *DC, SourceLocation ExternLoc, - SourceLocation LangLoc, LanguageIDs lang, bool HasBraces) - : Decl(LinkageSpec, DC, LangLoc), DeclContext(LinkageSpec), - Language(lang), HasBraces(HasBraces), ExternLoc(ExternLoc), - RBraceLoc(SourceLocation()) {} + SourceLocation LangLoc, LanguageIDs lang, bool HasBraces); public: static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC, @@ -2864,16 +2857,18 @@ public: static LinkageSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID); /// Return the language specified by this linkage specification. - LanguageIDs getLanguage() const { return LanguageIDs(Language); } + LanguageIDs getLanguage() const { + return static_cast<LanguageIDs>(LinkageSpecDeclBits.Language); + } /// Set the language specified by this linkage specification. - void setLanguage(LanguageIDs L) { Language = L; } + void setLanguage(LanguageIDs L) { LinkageSpecDeclBits.Language = L; } /// Determines whether this linkage specification had braces in /// its syntactic form. bool hasBraces() const { - assert(!RBraceLoc.isValid() || HasBraces); - return HasBraces; + assert(!RBraceLoc.isValid() || LinkageSpecDeclBits.HasBraces); + return LinkageSpecDeclBits.HasBraces; } SourceLocation getExternLoc() const { return ExternLoc; } @@ -2881,19 +2876,19 @@ public: void setExternLoc(SourceLocation L) { ExternLoc = L; } void setRBraceLoc(SourceLocation L) { RBraceLoc = L; - HasBraces = RBraceLoc.isValid(); + LinkageSpecDeclBits.HasBraces = RBraceLoc.isValid(); } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { if (hasBraces()) return getRBraceLoc(); // No braces: get the end location of the (only) declaration in context // (if present). - return decls_empty() ? getLocation() : decls_begin()->getLocEnd(); + return decls_empty() ? getLocation() : decls_begin()->getEndLoc(); } SourceRange getSourceRange() const override LLVM_READONLY { - return SourceRange(ExternLoc, getLocEnd()); + return SourceRange(ExternLoc, getEndLoc()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -3698,7 +3693,7 @@ class UnresolvedUsingTypenameDecl public: /// Returns the source location of the 'using' keyword. - SourceLocation getUsingLoc() const { return getLocStart(); } + SourceLocation getUsingLoc() const { return getBeginLoc(); } /// Returns the source location of the 'typename' keyword. SourceLocation getTypenameLoc() const { return TypenameLocation; } @@ -3923,6 +3918,7 @@ class MSPropertyDecl : public DeclaratorDecl { : DeclaratorDecl(MSProperty, DC, L, N, T, TInfo, StartL), GetterId(Getter), SetterId(Setter) {} + void anchor() override; public: friend class ASTDeclReader; diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h index a8de8ed16840..b5808f23de6f 100644 --- a/include/clang/AST/DeclFriend.h +++ b/include/clang/AST/DeclFriend.h @@ -158,7 +158,7 @@ public: if (DD->getOuterLocStart() != DD->getInnerLocStart()) return DD->getSourceRange(); } - return SourceRange(getFriendLoc(), ND->getLocEnd()); + return SourceRange(getFriendLoc(), ND->getEndLoc()); } else if (TypeSourceInfo *TInfo = getFriendType()) { SourceLocation StartL = diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index c1cc726e3152..5b57411f9785 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -137,62 +137,17 @@ public: /// the above methods are setMenu:, menu, replaceSubview:with:, and defaultMenu. /// class ObjCMethodDecl : public NamedDecl, public DeclContext { + // This class stores some data in DeclContext::ObjCMethodDeclBits + // to save some space. Use the provided accessors to access it. + public: enum ImplementationControl { None, Required, Optional }; private: - // The conventional meaning of this method; an ObjCMethodFamily. - // This is not serialized; instead, it is computed on demand and - // cached. - mutable unsigned Family : ObjCMethodFamilyBitWidth; - - /// instance (true) or class (false) method. - unsigned IsInstance : 1; - unsigned IsVariadic : 1; - - /// True if this method is the getter or setter for an explicit property. - unsigned IsPropertyAccessor : 1; - - // Method has a definition. - unsigned IsDefined : 1; - - /// Method redeclaration in the same interface. - unsigned IsRedeclaration : 1; - - /// Is redeclared in the same interface. - mutable unsigned HasRedeclaration : 1; - - // NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum - /// \@required/\@optional - unsigned DeclImplementation : 2; - - // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum - /// in, inout, etc. - unsigned objcDeclQualifier : 7; - - /// Indicates whether this method has a related result type. - unsigned RelatedResultType : 1; - - /// Whether the locations of the selector identifiers are in a - /// "standard" position, a enum SelectorLocationsKind. - unsigned SelLocsKind : 2; - - /// Whether this method overrides any other in the class hierarchy. - /// - /// A method is said to override any method in the class's - /// base classes, its protocols, or its categories' protocols, that has - /// the same selector and is of the same kind (class or instance). - /// A method in an implementation is not considered as overriding the same - /// method in the interface or its categories. - unsigned IsOverriding : 1; - - /// Indicates if the method was a definition but its body was skipped. - unsigned HasSkippedBody : 1; - - // Return type of this method. + /// Return type of this method. QualType MethodDeclType; - // Type source information for the return type. + /// Type source information for the return type. TypeSourceInfo *ReturnTInfo; /// Array of ParmVarDecls for the formal parameters of this method @@ -203,7 +158,7 @@ private: /// List of attributes for this method declaration. SourceLocation DeclEndLoc; // the location of the ';' or '{'. - // The following are only used for method definitions, null otherwise. + /// The following are only used for method definitions, null otherwise. LazyDeclStmtPtr Body; /// SelfDecl - Decl for the implicit self parameter. This is lazily @@ -220,21 +175,14 @@ private: bool isVariadic = false, bool isPropertyAccessor = false, bool isImplicitlyDeclared = false, bool isDefined = false, ImplementationControl impControl = None, - bool HasRelatedResultType = false) - : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), - DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily), - IsInstance(isInstance), IsVariadic(isVariadic), - IsPropertyAccessor(isPropertyAccessor), IsDefined(isDefined), - IsRedeclaration(0), HasRedeclaration(0), DeclImplementation(impControl), - objcDeclQualifier(OBJC_TQ_None), - RelatedResultType(HasRelatedResultType), - SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0), HasSkippedBody(0), - MethodDeclType(T), ReturnTInfo(ReturnTInfo), DeclEndLoc(endLoc) { - setImplicit(isImplicitlyDeclared); - } + bool HasRelatedResultType = false); SelectorLocationsKind getSelLocsKind() const { - return (SelectorLocationsKind)SelLocsKind; + return static_cast<SelectorLocationsKind>(ObjCMethodDeclBits.SelLocsKind); + } + + void setSelLocsKind(SelectorLocationsKind Kind) { + ObjCMethodDeclBits.SelLocsKind = Kind; } bool hasStandardSelLocs() const { @@ -244,10 +192,10 @@ private: /// Get a pointer to the stored selector identifiers locations array. /// No locations will be stored if HasStandardSelLocs is true. SourceLocation *getStoredSelLocs() { - return reinterpret_cast<SourceLocation*>(getParams() + NumParams); + return reinterpret_cast<SourceLocation *>(getParams() + NumParams); } const SourceLocation *getStoredSelLocs() const { - return reinterpret_cast<const SourceLocation*>(getParams() + NumParams); + return reinterpret_cast<const SourceLocation *>(getParams() + NumParams); } /// Get a pointer to the stored selector identifiers locations array. @@ -297,36 +245,50 @@ public: } ObjCDeclQualifier getObjCDeclQualifier() const { - return ObjCDeclQualifier(objcDeclQualifier); + return static_cast<ObjCDeclQualifier>(ObjCMethodDeclBits.objcDeclQualifier); + } + + void setObjCDeclQualifier(ObjCDeclQualifier QV) { + ObjCMethodDeclBits.objcDeclQualifier = QV; } - void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; } /// Determine whether this method has a result type that is related /// to the message receiver's type. - bool hasRelatedResultType() const { return RelatedResultType; } + bool hasRelatedResultType() const { + return ObjCMethodDeclBits.RelatedResultType; + } /// Note whether this method has a related result type. - void SetRelatedResultType(bool RRT = true) { RelatedResultType = RRT; } + void setRelatedResultType(bool RRT = true) { + ObjCMethodDeclBits.RelatedResultType = RRT; + } /// True if this is a method redeclaration in the same interface. - bool isRedeclaration() const { return IsRedeclaration; } + bool isRedeclaration() const { return ObjCMethodDeclBits.IsRedeclaration; } + void setIsRedeclaration(bool RD) { ObjCMethodDeclBits.IsRedeclaration = RD; } void setAsRedeclaration(const ObjCMethodDecl *PrevMethod); + /// True if redeclared in the same interface. + bool hasRedeclaration() const { return ObjCMethodDeclBits.HasRedeclaration; } + void setHasRedeclaration(bool HRD) const { + ObjCMethodDeclBits.HasRedeclaration = HRD; + } + /// Returns the location where the declarator ends. It will be /// the location of ';' for a method declaration and the location of '{' /// for a method definition. SourceLocation getDeclaratorEndLoc() const { return DeclEndLoc; } // Location information, modeled after the Stmt API. - SourceLocation getLocStart() const LLVM_READONLY { return getLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY { return getLocation(); } + SourceLocation getEndLoc() const LLVM_READONLY; SourceRange getSourceRange() const override LLVM_READONLY { - return SourceRange(getLocation(), getLocEnd()); + return SourceRange(getLocation(), getEndLoc()); } SourceLocation getSelectorStartLoc() const { if (isImplicit()) - return getLocStart(); + return getBeginLoc(); return getSelectorLoc(0); } @@ -407,6 +369,14 @@ public: NumParams); } + ParmVarDecl *getParamDecl(unsigned Idx) { + assert(Idx < NumParams && "Index out of bounds!"); + return getParams()[Idx]; + } + const ParmVarDecl *getParamDecl(unsigned Idx) const { + return const_cast<ObjCMethodDecl *>(this)->getParamDecl(Idx); + } + /// Sets the method's parameters and selector source locations. /// If the method is implicit (not coming from source) \p SelLocs is /// ignored. @@ -449,18 +419,26 @@ public: /// Determines the family of this method. ObjCMethodFamily getMethodFamily() const; - bool isInstanceMethod() const { return IsInstance; } - void setInstanceMethod(bool isInst) { IsInstance = isInst; } - bool isVariadic() const { return IsVariadic; } - void setVariadic(bool isVar) { IsVariadic = isVar; } + bool isInstanceMethod() const { return ObjCMethodDeclBits.IsInstance; } + void setInstanceMethod(bool isInst) { + ObjCMethodDeclBits.IsInstance = isInst; + } - bool isClassMethod() const { return !IsInstance; } + bool isVariadic() const { return ObjCMethodDeclBits.IsVariadic; } + void setVariadic(bool isVar) { ObjCMethodDeclBits.IsVariadic = isVar; } - bool isPropertyAccessor() const { return IsPropertyAccessor; } - void setPropertyAccessor(bool isAccessor) { IsPropertyAccessor = isAccessor; } + bool isClassMethod() const { return !isInstanceMethod(); } - bool isDefined() const { return IsDefined; } - void setDefined(bool isDefined) { IsDefined = isDefined; } + bool isPropertyAccessor() const { + return ObjCMethodDeclBits.IsPropertyAccessor; + } + + void setPropertyAccessor(bool isAccessor) { + ObjCMethodDeclBits.IsPropertyAccessor = isAccessor; + } + + bool isDefined() const { return ObjCMethodDeclBits.IsDefined; } + void setDefined(bool isDefined) { ObjCMethodDeclBits.IsDefined = isDefined; } /// Whether this method overrides any other in the class hierarchy. /// @@ -469,8 +447,8 @@ public: /// the same selector and is of the same kind (class or instance). /// A method in an implementation is not considered as overriding the same /// method in the interface or its categories. - bool isOverriding() const { return IsOverriding; } - void setOverriding(bool isOverriding) { IsOverriding = isOverriding; } + bool isOverriding() const { return ObjCMethodDeclBits.IsOverriding; } + void setOverriding(bool IsOver) { ObjCMethodDeclBits.IsOverriding = IsOver; } /// Return overridden methods for the given \p Method. /// @@ -484,8 +462,10 @@ public: SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const; /// True if the method was a definition but its body was skipped. - bool hasSkippedBody() const { return HasSkippedBody; } - void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; } + bool hasSkippedBody() const { return ObjCMethodDeclBits.HasSkippedBody; } + void setHasSkippedBody(bool Skipped = true) { + ObjCMethodDeclBits.HasSkippedBody = Skipped; + } /// Returns the property associated with this method's selector. /// @@ -496,11 +476,11 @@ public: // Related to protocols declared in \@protocol void setDeclImplementation(ImplementationControl ic) { - DeclImplementation = ic; + ObjCMethodDeclBits.DeclImplementation = ic; } ImplementationControl getImplementationControl() const { - return ImplementationControl(DeclImplementation); + return ImplementationControl(ObjCMethodDeclBits.DeclImplementation); } bool isOptional() const { @@ -534,6 +514,9 @@ public: /// Returns whether this specific method is a definition. bool isThisDeclarationADefinition() const { return hasBody(); } + /// Is this method defined in the NSObject base class? + bool definedInNSObject(const ASTContext &) const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCMethod; } @@ -984,7 +967,8 @@ public: /// ObjCProtocolDecl, and ObjCImplDecl. /// class ObjCContainerDecl : public NamedDecl, public DeclContext { - SourceLocation AtStart; + // This class stores some data in DeclContext::ObjCContainerDeclBits + // to save some space. Use the provided accessors to access it. // These two locations in the range mark the end of the method container. // The first points to the '@' token, and the second to the 'end' token. @@ -993,10 +977,8 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext { void anchor() override; public: - ObjCContainerDecl(Kind DK, DeclContext *DC, - IdentifierInfo *Id, SourceLocation nameLoc, - SourceLocation atStartLoc) - : NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK), AtStart(atStartLoc) {} + ObjCContainerDecl(Kind DK, DeclContext *DC, IdentifierInfo *Id, + SourceLocation nameLoc, SourceLocation atStartLoc); // Iterator access to instance/class properties. using prop_iterator = specific_decl_iterator<ObjCPropertyDecl>; @@ -1130,20 +1112,19 @@ public: virtual void collectPropertiesToImplement(PropertyMap &PM, PropertyDeclOrder &PO) const {} - SourceLocation getAtStartLoc() const { return AtStart; } - void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; } + SourceLocation getAtStartLoc() const { return ObjCContainerDeclBits.AtStart; } - // Marks the end of the container. - SourceRange getAtEndRange() const { - return AtEnd; + void setAtStartLoc(SourceLocation Loc) { + ObjCContainerDeclBits.AtStart = Loc; } - void setAtEndRange(SourceRange atEnd) { - AtEnd = atEnd; - } + // Marks the end of the container. + SourceRange getAtEndRange() const { return AtEnd; } + + void setAtEndRange(SourceRange atEnd) { AtEnd = atEnd; } SourceRange getSourceRange() const override LLVM_READONLY { - return SourceRange(AtStart, getAtEndRange().getEnd()); + return SourceRange(getAtStartLoc(), getAtEndRange().getEnd()); } // Implement isa/cast/dyncast/etc. @@ -2831,7 +2812,7 @@ public: SourceRange getSourceRange() const override LLVM_READONLY; - SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; } void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } ObjCPropertyDecl *getPropertyDecl() const { diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h index bec3acffc433..8540cc5b25b6 100644 --- a/include/clang/AST/DeclOpenMP.h +++ b/include/clang/AST/DeclOpenMP.h @@ -18,6 +18,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/Type.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/TrailingObjects.h" @@ -100,6 +101,8 @@ public: /// /// Here 'omp_out += omp_in' is a combiner and 'omp_priv = 0' is an initializer. class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext { + // This class stores some data in DeclContext::OMPDeclareReductionDeclBits + // to save some space. Use the provided accessors to access it. public: enum InitKind { CallInit, // Initialized by function call. @@ -110,11 +113,17 @@ public: private: friend class ASTDeclReader; /// Combiner for declare reduction construct. - Expr *Combiner; + Expr *Combiner = nullptr; /// Initializer for declare reduction construct. - Expr *Initializer; - /// Kind of initializer - function call or omp_priv<init_expr> initializtion. - InitKind InitializerKind = CallInit; + Expr *Initializer = nullptr; + /// In parameter of the combiner. + Expr *In = nullptr; + /// Out parameter of the combiner. + Expr *Out = nullptr; + /// Priv parameter of the initializer. + Expr *Priv = nullptr; + /// Orig parameter of the initializer. + Expr *Orig = nullptr; /// Reference to the previous declare reduction construct in the same /// scope with the same name. Required for proper templates instantiation if @@ -125,10 +134,7 @@ private: OMPDeclareReductionDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, QualType Ty, - OMPDeclareReductionDecl *PrevDeclInScope) - : ValueDecl(DK, DC, L, Name, Ty), DeclContext(DK), Combiner(nullptr), - Initializer(nullptr), InitializerKind(CallInit), - PrevDeclInScope(PrevDeclInScope) {} + OMPDeclareReductionDecl *PrevDeclInScope); void setPrevDeclInScope(OMPDeclareReductionDecl *Prev) { PrevDeclInScope = Prev; @@ -146,19 +152,43 @@ public: /// Get combiner expression of the declare reduction construct. Expr *getCombiner() { return Combiner; } const Expr *getCombiner() const { return Combiner; } + /// Get In variable of the combiner. + Expr *getCombinerIn() { return In; } + const Expr *getCombinerIn() const { return In; } + /// Get Out variable of the combiner. + Expr *getCombinerOut() { return Out; } + const Expr *getCombinerOut() const { return Out; } /// Set combiner expression for the declare reduction construct. void setCombiner(Expr *E) { Combiner = E; } + /// Set combiner In and Out vars. + void setCombinerData(Expr *InE, Expr *OutE) { + In = InE; + Out = OutE; + } /// Get initializer expression (if specified) of the declare reduction /// construct. Expr *getInitializer() { return Initializer; } const Expr *getInitializer() const { return Initializer; } /// Get initializer kind. - InitKind getInitializerKind() const { return InitializerKind; } + InitKind getInitializerKind() const { + return static_cast<InitKind>(OMPDeclareReductionDeclBits.InitializerKind); + } + /// Get Orig variable of the initializer. + Expr *getInitOrig() { return Orig; } + const Expr *getInitOrig() const { return Orig; } + /// Get Priv variable of the initializer. + Expr *getInitPriv() { return Priv; } + const Expr *getInitPriv() const { return Priv; } /// Set initializer expression for the declare reduction construct. void setInitializer(Expr *E, InitKind IK) { Initializer = E; - InitializerKind = IK; + OMPDeclareReductionDeclBits.InitializerKind = IK; + } + /// Set initializer Orig and Priv vars. + void setInitializerData(Expr *OrigE, Expr *PrivE) { + Orig = OrigE; + Priv = PrivE; } /// Get reference to previous declare reduction construct in the same @@ -210,6 +240,76 @@ public: static bool classofKind(Kind K) { return K == OMPCapturedExpr; } }; +/// This represents '#pragma omp requires...' directive. +/// For example +/// +/// \code +/// #pragma omp requires unified_address +/// \endcode +/// +class OMPRequiresDecl final + : public Decl, + private llvm::TrailingObjects<OMPRequiresDecl, OMPClause *> { + friend class ASTDeclReader; + friend TrailingObjects; + + // Number of clauses associated with this requires declaration + unsigned NumClauses = 0; + + virtual void anchor(); + + OMPRequiresDecl(Kind DK, DeclContext *DC, SourceLocation L) + : Decl(DK, DC, L), NumClauses(0) {} + + /// Returns an array of immutable clauses associated with this requires + /// declaration + ArrayRef<const OMPClause *> getClauses() const { + return llvm::makeArrayRef(getTrailingObjects<OMPClause *>(), NumClauses); + } + + /// Returns an array of clauses associated with this requires declaration + MutableArrayRef<OMPClause *> getClauses() { + return MutableArrayRef<OMPClause *>(getTrailingObjects<OMPClause *>(), + NumClauses); + } + + /// Sets an array of clauses to this requires declaration + void setClauses(ArrayRef<OMPClause *> CL); + +public: + /// Create requires node. + static OMPRequiresDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, ArrayRef<OMPClause *> CL); + /// Create deserialized requires node. + static OMPRequiresDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned N); + + using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator; + using clauselist_const_iterator = ArrayRef<const OMPClause *>::iterator; + using clauselist_range = llvm::iterator_range<clauselist_iterator>; + using clauselist_const_range = llvm::iterator_range<clauselist_const_iterator>; + + unsigned clauselist_size() const { return NumClauses; } + bool clauselist_empty() const { return NumClauses == 0; } + + clauselist_range clauselists() { + return clauselist_range(clauselist_begin(), clauselist_end()); + } + clauselist_const_range clauselists() const { + return clauselist_const_range(clauselist_begin(), clauselist_end()); + } + clauselist_iterator clauselist_begin() { return getClauses().begin(); } + clauselist_iterator clauselist_end() { return getClauses().end(); } + clauselist_const_iterator clauselist_begin() const { + return getClauses().begin(); + } + clauselist_const_iterator clauselist_end() const { + return getClauses().end(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == OMPRequires; } +}; } // end namespace clang #endif diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index e0ea7cb8b1b8..f6e3d8f300ba 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -751,6 +751,7 @@ class RedeclarableTemplateDecl : public TemplateDecl, return getMostRecentDecl(); } + void anchor() override; protected: template <typename EntryType> struct SpecEntryTraits { using DeclType = EntryType; @@ -1093,6 +1094,9 @@ public: /// template. ArrayRef<TemplateArgument> getInjectedTemplateArgs(); + /// Merge \p Prev with our RedeclarableTemplateDecl::Common. + void mergePrevDecl(FunctionTemplateDecl *Prev); + /// Create a function template node. static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h index 520a4a10bfe1..c6cbc9ff7faa 100644 --- a/include/clang/AST/DeclVisitor.h +++ b/include/clang/AST/DeclVisitor.h @@ -21,15 +21,12 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" namespace clang { namespace declvisitor { - -template <typename T> struct make_ptr { using type = T *; }; -template <typename T> struct make_const_ptr { using type = const T *; }; - /// A simple visitor class that helps create declaration visitors. template<template <typename> class Ptr, typename ImplClass, typename RetTy=void> class Base { @@ -66,16 +63,16 @@ public: /// /// This class does not preserve constness of Decl pointers (see also /// ConstDeclVisitor). -template<typename ImplClass, typename RetTy = void> +template <typename ImplClass, typename RetTy = void> class DeclVisitor - : public declvisitor::Base<declvisitor::make_ptr, ImplClass, RetTy> {}; + : public declvisitor::Base<std::add_pointer, ImplClass, RetTy> {}; /// A simple visitor class that helps create declaration visitors. /// /// This class preserves constness of Decl pointers (see also DeclVisitor). -template<typename ImplClass, typename RetTy = void> +template <typename ImplClass, typename RetTy = void> class ConstDeclVisitor - : public declvisitor::Base<declvisitor::make_const_ptr, ImplClass, RetTy> {}; + : public declvisitor::Base<llvm::make_const_ptr, ImplClass, RetTy> {}; } // namespace clang diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index 856f3ab5720e..62afae23ec79 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -14,11 +14,14 @@ #ifndef LLVM_CLANG_AST_DECLARATIONNAME_H #define LLVM_CLANG_AST_DECLARATIONNAME_H +#include "clang/AST/Type.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/FoldingSet.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/type_traits.h" #include <cassert> @@ -30,67 +33,195 @@ namespace clang { class ASTContext; template <typename> class CanQual; -class CXXDeductionGuideNameExtra; -class CXXLiteralOperatorIdName; -class CXXOperatorIdName; -class CXXSpecialName; -class DeclarationNameExtra; -class IdentifierInfo; +class DeclarationName; +class DeclarationNameTable; class MultiKeywordSelector; -enum OverloadedOperatorKind : int; struct PrintingPolicy; -class QualType; class TemplateDecl; -class Type; class TypeSourceInfo; class UsingDirectiveDecl; using CanQualType = CanQual<Type>; -/// DeclarationName - The name of a declaration. In the common case, -/// this just stores an IdentifierInfo pointer to a normal -/// name. However, it also provides encodings for Objective-C -/// selectors (optimizing zero- and one-argument selectors, which make -/// up 78% percent of all selectors in Cocoa.h) and special C++ names -/// for constructors, destructors, and conversion functions. -class DeclarationName { +namespace detail { + +/// CXXSpecialNameExtra records the type associated with one of the "special" +/// kinds of declaration names in C++, e.g., constructors, destructors, and +/// conversion functions. Note that CXXSpecialName is used for C++ constructor, +/// destructor and conversion functions, but the actual kind is not stored in +/// CXXSpecialName. Instead we use three different FoldingSet<CXXSpecialName> +/// in DeclarationNameTable. +class alignas(IdentifierInfoAlignment) CXXSpecialNameExtra + : public llvm::FoldingSetNode { + friend class clang::DeclarationName; + friend class clang::DeclarationNameTable; + + /// The type associated with this declaration name. + QualType Type; + + /// Extra information associated with this declaration name that + /// can be used by the front end. All bits are really needed + /// so it is not possible to stash something in the low order bits. + void *FETokenInfo; + + CXXSpecialNameExtra(QualType QT) : Type(QT), FETokenInfo(nullptr) {} + public: - /// NameKind - The kind of name this object contains. - enum NameKind { - Identifier, - ObjCZeroArgSelector, - ObjCOneArgSelector, - ObjCMultiArgSelector, - CXXConstructorName, - CXXDestructorName, - CXXConversionFunctionName, - CXXDeductionGuideName, - CXXOperatorName, - CXXLiteralOperatorName, - CXXUsingDirective - }; + void Profile(llvm::FoldingSetNodeID &ID) { + ID.AddPointer(Type.getAsOpaquePtr()); + } +}; - static const unsigned NumNameKinds = CXXUsingDirective + 1; +/// Contains extra information for the name of a C++ deduction guide. +class alignas(IdentifierInfoAlignment) CXXDeductionGuideNameExtra + : public detail::DeclarationNameExtra, + public llvm::FoldingSetNode { + friend class clang::DeclarationName; + friend class clang::DeclarationNameTable; -private: + /// The template named by the deduction guide. + TemplateDecl *Template; + + /// Extra information associated with this operator name that + /// can be used by the front end. All bits are really needed + /// so it is not possible to stash something in the low order bits. + void *FETokenInfo; + + CXXDeductionGuideNameExtra(TemplateDecl *TD) + : DeclarationNameExtra(CXXDeductionGuideName), Template(TD), + FETokenInfo(nullptr) {} + +public: + void Profile(llvm::FoldingSetNodeID &ID) { ID.AddPointer(Template); } +}; + +/// Contains extra information for the name of an overloaded operator +/// in C++, such as "operator+. This do not includes literal or conversion +/// operators. For literal operators see CXXLiteralOperatorIdName and for +/// conversion operators see CXXSpecialNameExtra. +class alignas(IdentifierInfoAlignment) CXXOperatorIdName { + friend class clang::DeclarationName; + friend class clang::DeclarationNameTable; + + /// The kind of this operator. + OverloadedOperatorKind Kind = OO_None; + + /// Extra information associated with this operator name that + /// can be used by the front end. All bits are really needed + /// so it is not possible to stash something in the low order bits. + void *FETokenInfo = nullptr; +}; + +/// Contains the actual identifier that makes up the +/// name of a C++ literal operator. +class alignas(IdentifierInfoAlignment) CXXLiteralOperatorIdName + : public detail::DeclarationNameExtra, + public llvm::FoldingSetNode { + friend class clang::DeclarationName; + friend class clang::DeclarationNameTable; + + IdentifierInfo *ID; + + /// Extra information associated with this operator name that + /// can be used by the front end. All bits are really needed + /// so it is not possible to stash something in the low order bits. + void *FETokenInfo; + + CXXLiteralOperatorIdName(IdentifierInfo *II) + : DeclarationNameExtra(CXXLiteralOperatorName), ID(II), + FETokenInfo(nullptr) {} + +public: + void Profile(llvm::FoldingSetNodeID &FSID) { FSID.AddPointer(ID); } +}; + +} // namespace detail + +/// The name of a declaration. In the common case, this just stores +/// an IdentifierInfo pointer to a normal name. However, it also provides +/// encodings for Objective-C selectors (optimizing zero- and one-argument +/// selectors, which make up 78% percent of all selectors in Cocoa.h), +/// special C++ names for constructors, destructors, and conversion functions, +/// and C++ overloaded operators. +class DeclarationName { friend class DeclarationNameTable; friend class NamedDecl; - /// StoredNameKind - The kind of name that is actually stored in the + /// StoredNameKind represent the kind of name that is actually stored in the /// upper bits of the Ptr field. This is only used internally. /// - /// Note: The entries here are synchronized with the entries in Selector, - /// for efficient translation between the two. + /// NameKind, StoredNameKind, and DeclarationNameExtra::ExtraKind + /// must satisfy the following properties. These properties enable + /// efficient conversion between the various kinds. + /// + /// * The first seven enumerators of StoredNameKind must have the same + /// numerical value as the first seven enumerators of NameKind. + /// This enable efficient conversion between the two enumerations + /// in the usual case. + /// + /// * The enumerations values of DeclarationNameExtra::ExtraKind must start + /// at zero, and correspond to the numerical value of the first non-inline + /// enumeration values of NameKind minus an offset. This makes conversion + /// between DeclarationNameExtra::ExtraKind and NameKind possible with + /// a single addition/substraction. + /// + /// * The enumeration values of Selector::IdentifierInfoFlag must correspond + /// to the relevant enumeration values of StoredNameKind. + /// More specifically: + /// * ZeroArg == StoredObjCZeroArgSelector, + /// * OneArg == StoredObjCOneArgSelector, + /// * MultiArg == StoredDeclarationNameExtra + /// + /// * PtrMask must mask the low 3 bits of Ptr. enum StoredNameKind { StoredIdentifier = 0, - StoredObjCZeroArgSelector = 0x01, - StoredObjCOneArgSelector = 0x02, - StoredDeclarationNameExtra = 0x03, - PtrMask = 0x03 + StoredObjCZeroArgSelector = Selector::ZeroArg, + StoredObjCOneArgSelector = Selector::OneArg, + StoredCXXConstructorName = 3, + StoredCXXDestructorName = 4, + StoredCXXConversionFunctionName = 5, + StoredCXXOperatorName = 6, + StoredDeclarationNameExtra = Selector::MultiArg, + PtrMask = 7, + UncommonNameKindOffset = 8 + }; + + static_assert(alignof(IdentifierInfo) >= 8 && + alignof(detail::DeclarationNameExtra) >= 8 && + alignof(detail::CXXSpecialNameExtra) >= 8 && + alignof(detail::CXXOperatorIdName) >= 8 && + alignof(detail::CXXDeductionGuideNameExtra) >= 8 && + alignof(detail::CXXLiteralOperatorIdName) >= 8, + "The various classes that DeclarationName::Ptr can point to" + " must be at least aligned to 8 bytes!"); + +public: + /// The kind of the name stored in this DeclarationName. + /// The first 7 enumeration values are stored inline and correspond + /// to frequently used kinds. The rest is stored in DeclarationNameExtra + /// and correspond to infrequently used kinds. + enum NameKind { + Identifier = StoredIdentifier, + ObjCZeroArgSelector = StoredObjCZeroArgSelector, + ObjCOneArgSelector = StoredObjCOneArgSelector, + CXXConstructorName = StoredCXXConstructorName, + CXXDestructorName = StoredCXXDestructorName, + CXXConversionFunctionName = StoredCXXConversionFunctionName, + CXXOperatorName = StoredCXXOperatorName, + CXXDeductionGuideName = UncommonNameKindOffset + + detail::DeclarationNameExtra::CXXDeductionGuideName, + CXXLiteralOperatorName = + UncommonNameKindOffset + + detail::DeclarationNameExtra::CXXLiteralOperatorName, + CXXUsingDirective = UncommonNameKindOffset + + detail::DeclarationNameExtra::CXXUsingDirective, + ObjCMultiArgSelector = UncommonNameKindOffset + + detail::DeclarationNameExtra::ObjCMultiArgSelector }; - /// Ptr - The lowest two bits are used to express what kind of name - /// we're actually storing, using the values of NameKind. Depending +private: + /// The lowest three bits of Ptr are used to express what kind of name + /// we're actually storing, using the values of StoredNameKind. Depending /// on the kind of name this is, the upper bits of Ptr may have one /// of several different meanings: /// @@ -105,99 +236,141 @@ private: /// with one argument, and Ptr is an IdentifierInfo pointer /// pointing to the selector name. /// + /// StoredCXXConstructorName - The name of a C++ constructor, + /// Ptr points to a CXXSpecialNameExtra. + /// + /// StoredCXXDestructorName - The name of a C++ destructor, + /// Ptr points to a CXXSpecialNameExtra. + /// + /// StoredCXXConversionFunctionName - The name of a C++ conversion function, + /// Ptr points to a CXXSpecialNameExtra. + /// + /// StoredCXXOperatorName - The name of an overloaded C++ operator, + /// Ptr points to a CXXOperatorIdName. + /// /// StoredDeclarationNameExtra - Ptr is actually a pointer to a /// DeclarationNameExtra structure, whose first value will tell us - /// whether this is an Objective-C selector, C++ operator-id name, - /// or special C++ name. + /// whether this is an Objective-C selector, C++ deduction guide, + /// C++ literal operator, or C++ using directive. uintptr_t Ptr = 0; - // Construct a declaration name from the name of a C++ constructor, - // destructor, or conversion function. - DeclarationName(DeclarationNameExtra *Name) - : Ptr(reinterpret_cast<uintptr_t>(Name)) { - assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra"); - Ptr |= StoredDeclarationNameExtra; + StoredNameKind getStoredNameKind() const { + return static_cast<StoredNameKind>(Ptr & PtrMask); } - /// Construct a declaration name from a raw pointer. - DeclarationName(uintptr_t Ptr) : Ptr(Ptr) {} + void *getPtr() const { return reinterpret_cast<void *>(Ptr & ~PtrMask); } - /// getStoredNameKind - Return the kind of object that is stored in - /// Ptr. - StoredNameKind getStoredNameKind() const { - return static_cast<StoredNameKind>(Ptr & PtrMask); + void setPtrAndKind(const void *P, StoredNameKind Kind) { + uintptr_t PAsInteger = reinterpret_cast<uintptr_t>(P); + assert((Kind & ~PtrMask) == 0 && + "Invalid StoredNameKind in setPtrAndKind!"); + assert((PAsInteger & PtrMask) == 0 && + "Improperly aligned pointer in setPtrAndKind!"); + Ptr = PAsInteger | Kind; } - /// getExtra - Get the "extra" information associated with this - /// multi-argument selector or C++ special name. - DeclarationNameExtra *getExtra() const { - assert(getStoredNameKind() == StoredDeclarationNameExtra && - "Declaration name does not store an Extra structure"); - return reinterpret_cast<DeclarationNameExtra *>(Ptr & ~PtrMask); + /// Construct a declaration name from a DeclarationNameExtra. + DeclarationName(detail::DeclarationNameExtra *Name) { + setPtrAndKind(Name, StoredDeclarationNameExtra); } - /// getAsCXXSpecialName - If the stored pointer is actually a - /// CXXSpecialName, returns a pointer to it. Otherwise, returns - /// a NULL pointer. - CXXSpecialName *getAsCXXSpecialName() const { - NameKind Kind = getNameKind(); - if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName) - return reinterpret_cast<CXXSpecialName *>(getExtra()); - return nullptr; + /// Construct a declaration name from a CXXSpecialNameExtra. + DeclarationName(detail::CXXSpecialNameExtra *Name, + StoredNameKind StoredKind) { + assert((StoredKind == StoredCXXConstructorName || + StoredKind == StoredCXXDestructorName || + StoredKind == StoredCXXConversionFunctionName) && + "Invalid StoredNameKind when constructing a DeclarationName" + " from a CXXSpecialNameExtra!"); + setPtrAndKind(Name, StoredKind); } - /// If the stored pointer is actually a CXXDeductionGuideNameExtra, returns a - /// pointer to it. Otherwise, returns a NULL pointer. - CXXDeductionGuideNameExtra *getAsCXXDeductionGuideNameExtra() const { - if (getNameKind() == CXXDeductionGuideName) - return reinterpret_cast<CXXDeductionGuideNameExtra *>(getExtra()); - return nullptr; + /// Construct a DeclarationName from a CXXOperatorIdName. + DeclarationName(detail::CXXOperatorIdName *Name) { + setPtrAndKind(Name, StoredCXXOperatorName); } - /// getAsCXXOperatorIdName - CXXOperatorIdName *getAsCXXOperatorIdName() const { - if (getNameKind() == CXXOperatorName) - return reinterpret_cast<CXXOperatorIdName *>(getExtra()); - return nullptr; + /// Assert that the stored pointer points to an IdentifierInfo and return it. + IdentifierInfo *castAsIdentifierInfo() const { + assert((getStoredNameKind() == StoredIdentifier) && + "DeclarationName does not store an IdentifierInfo!"); + return static_cast<IdentifierInfo *>(getPtr()); } - CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const { - if (getNameKind() == CXXLiteralOperatorName) - return reinterpret_cast<CXXLiteralOperatorIdName *>(getExtra()); - return nullptr; + /// Assert that the stored pointer points to a DeclarationNameExtra + /// and return it. + detail::DeclarationNameExtra *castAsExtra() const { + assert((getStoredNameKind() == StoredDeclarationNameExtra) && + "DeclarationName does not store an Extra structure!"); + return static_cast<detail::DeclarationNameExtra *>(getPtr()); } - /// getFETokenInfoAsVoidSlow - Retrieves the front end-specified pointer - /// for this name as a void pointer if it's not an identifier. - void *getFETokenInfoAsVoidSlow() const; + /// Assert that the stored pointer points to a CXXSpecialNameExtra + /// and return it. + detail::CXXSpecialNameExtra *castAsCXXSpecialNameExtra() const { + assert((getStoredNameKind() == StoredCXXConstructorName || + getStoredNameKind() == StoredCXXDestructorName || + getStoredNameKind() == StoredCXXConversionFunctionName) && + "DeclarationName does not store a CXXSpecialNameExtra!"); + return static_cast<detail::CXXSpecialNameExtra *>(getPtr()); + } + + /// Assert that the stored pointer points to a CXXOperatorIdName + /// and return it. + detail::CXXOperatorIdName *castAsCXXOperatorIdName() const { + assert((getStoredNameKind() == StoredCXXOperatorName) && + "DeclarationName does not store a CXXOperatorIdName!"); + return static_cast<detail::CXXOperatorIdName *>(getPtr()); + } + + /// Assert that the stored pointer points to a CXXDeductionGuideNameExtra + /// and return it. + detail::CXXDeductionGuideNameExtra *castAsCXXDeductionGuideNameExtra() const { + assert(getNameKind() == CXXDeductionGuideName && + "DeclarationName does not store a CXXDeductionGuideNameExtra!"); + return static_cast<detail::CXXDeductionGuideNameExtra *>(getPtr()); + } + + /// Assert that the stored pointer points to a CXXLiteralOperatorIdName + /// and return it. + detail::CXXLiteralOperatorIdName *castAsCXXLiteralOperatorIdName() const { + assert(getNameKind() == CXXLiteralOperatorName && + "DeclarationName does not store a CXXLiteralOperatorIdName!"); + return static_cast<detail::CXXLiteralOperatorIdName *>(getPtr()); + } + + /// Get and set the FETokenInfo in the less common cases where the + /// declaration name do not point to an identifier. + void *getFETokenInfoSlow() const; + void setFETokenInfoSlow(void *T); public: - /// DeclarationName - Used to create an empty selector. - DeclarationName() = default; + /// Construct an empty declaration name. + DeclarationName() { setPtrAndKind(nullptr, StoredIdentifier); } - // Construct a declaration name from an IdentifierInfo *. - DeclarationName(const IdentifierInfo *II) - : Ptr(reinterpret_cast<uintptr_t>(II)) { - assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo"); + /// Construct a declaration name from an IdentifierInfo *. + DeclarationName(const IdentifierInfo *II) { + setPtrAndKind(II, StoredIdentifier); } - // Construct a declaration name from an Objective-C selector. + /// Construct a declaration name from an Objective-C selector. DeclarationName(Selector Sel) : Ptr(Sel.InfoPtr) {} - /// getUsingDirectiveName - Return name for all using-directives. - static DeclarationName getUsingDirectiveName(); + /// Returns the name for all C++ using-directives. + static DeclarationName getUsingDirectiveName() { + // Single instance of DeclarationNameExtra for using-directive + static detail::DeclarationNameExtra UDirExtra( + detail::DeclarationNameExtra::CXXUsingDirective); + return DeclarationName(&UDirExtra); + } - // operator bool() - Evaluates true when this declaration name is - // non-empty. + /// Evaluates true when this declaration name is non-empty. explicit operator bool() const { - return ((Ptr & PtrMask) != 0) || - (reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask)); + return getPtr() || (getStoredNameKind() != StoredIdentifier); } /// Evaluates true when this declaration name is empty. - bool isEmpty() const { - return !*this; - } + bool isEmpty() const { return !*this; } /// Predicate functions for querying what type of name this is. bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; } @@ -208,8 +381,19 @@ public: return getStoredNameKind() == StoredObjCOneArgSelector; } - /// getNameKind - Determine what kind of name this is. - NameKind getNameKind() const; + /// Determine what kind of name this is. + NameKind getNameKind() const { + // We rely on the fact that the first 7 NameKind and StoredNameKind + // have the same numerical value. This makes the usual case efficient. + StoredNameKind StoredKind = getStoredNameKind(); + if (StoredKind != StoredDeclarationNameExtra) + return static_cast<NameKind>(StoredKind); + // We have to consult DeclarationNameExtra. We rely on the fact that the + // enumeration values of ExtraKind correspond to the enumeration values of + // NameKind minus an offset of UncommonNameKindOffset. + unsigned ExtraKind = castAsExtra()->getKind(); + return static_cast<NameKind>(UncommonNameKindOffset + ExtraKind); + } /// Determines whether the name itself is dependent, e.g., because it /// involves a C++ type that is itself dependent. @@ -219,95 +403,128 @@ public: /// callee in a call expression with dependent arguments. bool isDependentName() const; - /// getNameAsString - Retrieve the human-readable string for this name. + /// Retrieve the human-readable string for this name. std::string getAsString() const; - /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in - /// this declaration name, or NULL if this declaration name isn't a - /// simple identifier. + /// Retrieve the IdentifierInfo * stored in this declaration name, + /// or null if this declaration name isn't a simple identifier. IdentifierInfo *getAsIdentifierInfo() const { if (isIdentifier()) - return reinterpret_cast<IdentifierInfo *>(Ptr); + return castAsIdentifierInfo(); return nullptr; } - /// getAsOpaqueInteger - Get the representation of this declaration - /// name as an opaque integer. + /// Get the representation of this declaration name as an opaque integer. uintptr_t getAsOpaqueInteger() const { return Ptr; } - /// getAsOpaquePtr - Get the representation of this declaration name as - /// an opaque pointer. - void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); } + /// Get the representation of this declaration name as an opaque pointer. + void *getAsOpaquePtr() const { return reinterpret_cast<void *>(Ptr); } + /// Get a declaration name from an opaque pointer returned by getAsOpaquePtr. static DeclarationName getFromOpaquePtr(void *P) { DeclarationName N; - N.Ptr = reinterpret_cast<uintptr_t> (P); + N.Ptr = reinterpret_cast<uintptr_t>(P); return N; } + /// Get a declaration name from an opaque integer + /// returned by getAsOpaqueInteger. static DeclarationName getFromOpaqueInteger(uintptr_t P) { DeclarationName N; N.Ptr = P; return N; } - /// getCXXNameType - If this name is one of the C++ names (of a - /// constructor, destructor, or conversion function), return the - /// type associated with that name. - QualType getCXXNameType() const; + /// If this name is one of the C++ names (of a constructor, destructor, + /// or conversion function), return the type associated with that name. + QualType getCXXNameType() const { + if (getStoredNameKind() == StoredCXXConstructorName || + getStoredNameKind() == StoredCXXDestructorName || + getStoredNameKind() == StoredCXXConversionFunctionName) { + assert(getPtr() && "getCXXNameType on a null DeclarationName!"); + return castAsCXXSpecialNameExtra()->Type; + } + return QualType(); + } /// If this name is the name of a C++ deduction guide, return the /// template associated with that name. - TemplateDecl *getCXXDeductionGuideTemplate() const; + TemplateDecl *getCXXDeductionGuideTemplate() const { + if (getNameKind() == CXXDeductionGuideName) { + assert(getPtr() && + "getCXXDeductionGuideTemplate on a null DeclarationName!"); + return castAsCXXDeductionGuideNameExtra()->Template; + } + return nullptr; + } - /// getCXXOverloadedOperator - If this name is the name of an - /// overloadable operator in C++ (e.g., @c operator+), retrieve the - /// kind of overloaded operator. - OverloadedOperatorKind getCXXOverloadedOperator() const; + /// If this name is the name of an overloadable operator in C++ + /// (e.g., @c operator+), retrieve the kind of overloaded operator. + OverloadedOperatorKind getCXXOverloadedOperator() const { + if (getStoredNameKind() == StoredCXXOperatorName) { + assert(getPtr() && "getCXXOverloadedOperator on a null DeclarationName!"); + return castAsCXXOperatorIdName()->Kind; + } + return OO_None; + } - /// getCXXLiteralIdentifier - If this name is the name of a literal - /// operator, retrieve the identifier associated with it. - IdentifierInfo *getCXXLiteralIdentifier() const; + /// If this name is the name of a literal operator, + /// retrieve the identifier associated with it. + IdentifierInfo *getCXXLiteralIdentifier() const { + if (getNameKind() == CXXLiteralOperatorName) { + assert(getPtr() && "getCXXLiteralIdentifier on a null DeclarationName!"); + return castAsCXXLiteralOperatorIdName()->ID; + } + return nullptr; + } - /// getObjCSelector - Get the Objective-C selector stored in this - /// declaration name. + /// Get the Objective-C selector stored in this declaration name. Selector getObjCSelector() const { assert((getNameKind() == ObjCZeroArgSelector || getNameKind() == ObjCOneArgSelector || - getNameKind() == ObjCMultiArgSelector || - Ptr == 0) && "Not a selector!"); + getNameKind() == ObjCMultiArgSelector || !getPtr()) && + "Not a selector!"); return Selector(Ptr); } - /// getFETokenInfo/setFETokenInfo - The language front-end is - /// allowed to associate arbitrary metadata with some kinds of - /// declaration names, including normal identifiers and C++ - /// constructors, destructors, and conversion functions. - template<typename T> - T *getFETokenInfo() const { - if (const IdentifierInfo *Info = getAsIdentifierInfo()) - return Info->getFETokenInfo<T>(); - return static_cast<T*>(getFETokenInfoAsVoidSlow()); + /// Get and set FETokenInfo. The language front-end is allowed to associate + /// arbitrary metadata with some kinds of declaration names, including normal + /// identifiers and C++ constructors, destructors, and conversion functions. + void *getFETokenInfo() const { + assert(getPtr() && "getFETokenInfo on an empty DeclarationName!"); + if (getStoredNameKind() == StoredIdentifier) + return castAsIdentifierInfo()->getFETokenInfo(); + return getFETokenInfoSlow(); } - void setFETokenInfo(void *T); + void setFETokenInfo(void *T) { + assert(getPtr() && "setFETokenInfo on an empty DeclarationName!"); + if (getStoredNameKind() == StoredIdentifier) + castAsIdentifierInfo()->setFETokenInfo(T); + else + setFETokenInfoSlow(T); + } - /// operator== - Determine whether the specified names are identical.. + /// Determine whether the specified names are identical. friend bool operator==(DeclarationName LHS, DeclarationName RHS) { return LHS.Ptr == RHS.Ptr; } - /// operator!= - Determine whether the specified names are different. + /// Determine whether the specified names are different. friend bool operator!=(DeclarationName LHS, DeclarationName RHS) { return LHS.Ptr != RHS.Ptr; } static DeclarationName getEmptyMarker() { - return DeclarationName(uintptr_t(-1)); + DeclarationName Name; + Name.Ptr = uintptr_t(-1); + return Name; } static DeclarationName getTombstoneMarker() { - return DeclarationName(uintptr_t(-2)); + DeclarationName Name; + Name.Ptr = uintptr_t(-2); + return Name; } static int compare(DeclarationName LHS, DeclarationName RHS); @@ -343,67 +560,88 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) { return DeclarationName::compare(LHS, RHS) >= 0; } -/// DeclarationNameTable - Used to store and retrieve DeclarationName +/// DeclarationNameTable is used to store and retrieve DeclarationName /// instances for the various kinds of declaration names, e.g., normal /// identifiers, C++ constructor names, etc. This class contains /// uniqued versions of each of the C++ special names, which can be -/// retrieved using its member functions (e.g., -/// getCXXConstructorName). +/// retrieved using its member functions (e.g., getCXXConstructorName). class DeclarationNameTable { + /// Used to allocate elements in the FoldingSets below. const ASTContext &Ctx; - // Actually a FoldingSet<CXXSpecialName> * - void *CXXSpecialNamesImpl; + /// Manage the uniqued CXXSpecialNameExtra representing C++ constructors. + /// getCXXConstructorName and getCXXSpecialName can be used to obtain + /// a DeclarationName from the corresponding type of the constructor. + llvm::FoldingSet<detail::CXXSpecialNameExtra> CXXConstructorNames; + + /// Manage the uniqued CXXSpecialNameExtra representing C++ destructors. + /// getCXXDestructorName and getCXXSpecialName can be used to obtain + /// a DeclarationName from the corresponding type of the destructor. + llvm::FoldingSet<detail::CXXSpecialNameExtra> CXXDestructorNames; - // Operator names - CXXOperatorIdName *CXXOperatorNames; + /// Manage the uniqued CXXSpecialNameExtra representing C++ conversion + /// functions. getCXXConversionFunctionName and getCXXSpecialName can be + /// used to obtain a DeclarationName from the corresponding type of the + /// conversion function. + llvm::FoldingSet<detail::CXXSpecialNameExtra> CXXConversionFunctionNames; - // Actually a CXXOperatorIdName* - void *CXXLiteralOperatorNames; + /// Manage the uniqued CXXOperatorIdName, which contain extra information + /// for the name of overloaded C++ operators. getCXXOperatorName + /// can be used to obtain a DeclarationName from the operator kind. + detail::CXXOperatorIdName CXXOperatorNames[NUM_OVERLOADED_OPERATORS]; - // FoldingSet<CXXDeductionGuideNameExtra> * - void *CXXDeductionGuideNames; + /// Manage the uniqued CXXLiteralOperatorIdName, which contain extra + /// information for the name of C++ literal operators. + /// getCXXLiteralOperatorName can be used to obtain a DeclarationName + /// from the corresponding IdentifierInfo. + llvm::FoldingSet<detail::CXXLiteralOperatorIdName> CXXLiteralOperatorNames; + + /// Manage the uniqued CXXDeductionGuideNameExtra, which contain + /// extra information for the name of a C++ deduction guide. + /// getCXXDeductionGuideName can be used to obtain a DeclarationName + /// from the corresponding template declaration. + llvm::FoldingSet<detail::CXXDeductionGuideNameExtra> CXXDeductionGuideNames; public: DeclarationNameTable(const ASTContext &C); DeclarationNameTable(const DeclarationNameTable &) = delete; DeclarationNameTable &operator=(const DeclarationNameTable &) = delete; + DeclarationNameTable(DeclarationNameTable &&) = delete; + DeclarationNameTable &operator=(DeclarationNameTable &&) = delete; + ~DeclarationNameTable() = default; - ~DeclarationNameTable(); - - /// getIdentifier - Create a declaration name that is a simple - /// identifier. + /// Create a declaration name that is a simple identifier. DeclarationName getIdentifier(const IdentifierInfo *ID) { return DeclarationName(ID); } - /// getCXXConstructorName - Returns the name of a C++ constructor - /// for the given Type. + /// Returns the name of a C++ constructor for the given Type. DeclarationName getCXXConstructorName(CanQualType Ty); - /// getCXXDestructorName - Returns the name of a C++ destructor - /// for the given Type. + /// Returns the name of a C++ destructor for the given Type. DeclarationName getCXXDestructorName(CanQualType Ty); /// Returns the name of a C++ deduction guide for the given template. DeclarationName getCXXDeductionGuideName(TemplateDecl *TD); - /// getCXXConversionFunctionName - Returns the name of a C++ - /// conversion function for the given Type. + /// Returns the name of a C++ conversion function for the given Type. DeclarationName getCXXConversionFunctionName(CanQualType Ty); - /// getCXXSpecialName - Returns a declaration name for special kind - /// of C++ name, e.g., for a constructor, destructor, or conversion - /// function. + /// Returns a declaration name for special kind of C++ name, + /// e.g., for a constructor, destructor, or conversion function. + /// Kind must be one of: + /// * DeclarationName::CXXConstructorName, + /// * DeclarationName::CXXDestructorName or + /// * DeclarationName::CXXConversionFunctionName DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind, CanQualType Ty); - /// getCXXOperatorName - Get the name of the overloadable C++ - /// operator corresponding to Op. - DeclarationName getCXXOperatorName(OverloadedOperatorKind Op); + /// Get the name of the overloadable C++ operator corresponding to Op. + DeclarationName getCXXOperatorName(OverloadedOperatorKind Op) { + return DeclarationName(&CXXOperatorNames[Op]); + } - /// getCXXLiteralOperatorName - Get the name of the literal operator function - /// with II as the identifier. + /// Get the name of the literal operator function with II as the identifier. DeclarationName getCXXLiteralOperatorName(IdentifierInfo *II); }; @@ -491,9 +729,10 @@ public: /// getNamedTypeInfo - Returns the source type info associated to /// the name. Assumes it is a constructor, destructor or conversion. TypeSourceInfo *getNamedTypeInfo() const { - assert(Name.getNameKind() == DeclarationName::CXXConstructorName || - Name.getNameKind() == DeclarationName::CXXDestructorName || - Name.getNameKind() == DeclarationName::CXXConversionFunctionName); + if (Name.getNameKind() != DeclarationName::CXXConstructorName && + Name.getNameKind() != DeclarationName::CXXDestructorName && + Name.getNameKind() != DeclarationName::CXXConversionFunctionName) + return nullptr; return LocInfo.NamedType.TInfo; } @@ -509,7 +748,8 @@ public: /// getCXXOperatorNameRange - Gets the range of the operator name /// (without the operator keyword). Assumes it is a (non-literal) operator. SourceRange getCXXOperatorNameRange() const { - assert(Name.getNameKind() == DeclarationName::CXXOperatorName); + if (Name.getNameKind() != DeclarationName::CXXOperatorName) + return SourceRange(); return SourceRange( SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.BeginOpNameLoc), SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.EndOpNameLoc) @@ -528,7 +768,8 @@ public: /// operator name (not the operator keyword). /// Assumes it is a literal operator. SourceLocation getCXXLiteralOperatorNameLoc() const { - assert(Name.getNameKind() == DeclarationName::CXXLiteralOperatorName); + if (Name.getNameKind() != DeclarationName::CXXLiteralOperatorName) + return SourceLocation(); return SourceLocation:: getFromRawEncoding(LocInfo.CXXLiteralOperatorName.OpNameLoc); } @@ -557,22 +798,16 @@ public: /// getBeginLoc - Retrieve the location of the first token. SourceLocation getBeginLoc() const { return NameLoc; } - /// getEndLoc - Retrieve the location of the last token. - SourceLocation getEndLoc() const { return getLocEnd(); } - /// getSourceRange - The range of the declaration name. SourceRange getSourceRange() const LLVM_READONLY { - return SourceRange(getLocStart(), getLocEnd()); + return SourceRange(getBeginLoc(), getEndLoc()); } - SourceLocation getLocStart() const LLVM_READONLY { - return getBeginLoc(); - } - - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { SourceLocation EndLoc = getEndLocPrivate(); - return EndLoc.isValid() ? EndLoc : getLocStart(); + return EndLoc.isValid() ? EndLoc : getBeginLoc(); } + private: SourceLocation getEndLocPrivate() const; }; diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h index 1aec5ae842d4..f356584144e6 100644 --- a/include/clang/AST/EvaluatedExprVisitor.h +++ b/include/clang/AST/EvaluatedExprVisitor.h @@ -19,6 +19,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtVisitor.h" +#include "llvm/ADT/STLExtras.h" namespace clang { @@ -107,23 +108,22 @@ public: }; /// EvaluatedExprVisitor - This class visits 'Expr *'s -template<typename ImplClass> +template <typename ImplClass> class EvaluatedExprVisitor - : public EvaluatedExprVisitorBase<make_ptr, ImplClass> { + : public EvaluatedExprVisitorBase<std::add_pointer, ImplClass> { public: - explicit EvaluatedExprVisitor(const ASTContext &Context) : - EvaluatedExprVisitorBase<make_ptr, ImplClass>(Context) { } + explicit EvaluatedExprVisitor(const ASTContext &Context) + : EvaluatedExprVisitorBase<std::add_pointer, ImplClass>(Context) {} }; /// ConstEvaluatedExprVisitor - This class visits 'const Expr *'s. -template<typename ImplClass> +template <typename ImplClass> class ConstEvaluatedExprVisitor - : public EvaluatedExprVisitorBase<make_const_ptr, ImplClass> { + : public EvaluatedExprVisitorBase<llvm::make_const_ptr, ImplClass> { public: - explicit ConstEvaluatedExprVisitor(const ASTContext &Context) : - EvaluatedExprVisitorBase<make_const_ptr, ImplClass>(Context) { } + explicit ConstEvaluatedExprVisitor(const ASTContext &Context) + : EvaluatedExprVisitorBase<llvm::make_const_ptr, ImplClass>(Context) {} }; - } #endif // LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index c18fbf05df68..3de73428829b 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -32,6 +32,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/TrailingObjects.h" namespace clang { class APValue; @@ -99,10 +100,9 @@ struct SubobjectAdjustment { } }; -/// Expr - This represents one expression. Note that Expr's are subclasses of -/// Stmt. This allows an expression to be transparently used any place a Stmt -/// is required. -/// +/// This represents one expression. Note that Expr's are subclasses of Stmt. +/// This allows an expression to be transparently used any place a Stmt is +/// required. class Expr : public Stmt { QualType TR; @@ -583,7 +583,8 @@ public: /// this function returns true, it returns the folded constant in Result. If /// the expression is a glvalue, an lvalue-to-rvalue conversion will be /// applied. - bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const; + bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, + bool InConstantContext = false) const; /// EvaluateAsBooleanCondition - Return true if this is a constant /// which we can fold and convert to a boolean condition using @@ -600,7 +601,7 @@ public: /// EvaluateAsInt - Return true if this is a constant which we can fold and /// convert to an integer, using any crazy technique that we want to. - bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx, + bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; /// EvaluateAsFloat - Return true if this is a constant which we can fold and @@ -632,8 +633,13 @@ public: /// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded /// integer. This must be called on an expression that constant folds to an /// integer. - llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, - SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr) const; + llvm::APSInt EvaluateKnownConstInt( + const ASTContext &Ctx, + SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr) const; + + llvm::APSInt EvaluateKnownConstIntCheckOverflow( + const ASTContext &Ctx, + SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr) const; void EvaluateForOverflow(const ASTContext &Ctx) const; @@ -864,6 +870,70 @@ public: }; //===----------------------------------------------------------------------===// +// Wrapper Expressions. +//===----------------------------------------------------------------------===// + +/// FullExpr - Represents a "full-expression" node. +class FullExpr : public Expr { +protected: + Stmt *SubExpr; + + FullExpr(StmtClass SC, Expr *subexpr) + : Expr(SC, subexpr->getType(), + subexpr->getValueKind(), subexpr->getObjectKind(), + subexpr->isTypeDependent(), subexpr->isValueDependent(), + subexpr->isInstantiationDependent(), + subexpr->containsUnexpandedParameterPack()), SubExpr(subexpr) {} + FullExpr(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty) {} +public: + const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } + Expr *getSubExpr() { return cast<Expr>(SubExpr); } + + /// As with any mutator of the AST, be very careful when modifying an + /// existing AST to preserve its invariants. + void setSubExpr(Expr *E) { SubExpr = E; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstFullExprConstant && + T->getStmtClass() <= lastFullExprConstant; + } +}; + +/// ConstantExpr - An expression that occurs in a constant context. +class ConstantExpr : public FullExpr { + ConstantExpr(Expr *subexpr) + : FullExpr(ConstantExprClass, subexpr) {} + +public: + static ConstantExpr *Create(const ASTContext &Context, Expr *E) { + assert(!isa<ConstantExpr>(E)); + return new (Context) ConstantExpr(E); + } + + /// Build an empty constant expression wrapper. + explicit ConstantExpr(EmptyShell Empty) + : FullExpr(ConstantExprClass, Empty) {} + + SourceLocation getBeginLoc() const LLVM_READONLY { + return SubExpr->getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY { + return SubExpr->getEndLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConstantExprClass; + } + + // Iterators + child_range children() { return child_range(&SubExpr, &SubExpr+1); } + const_child_range children() const { + return const_child_range(&SubExpr, &SubExpr + 1); + } +}; + +//===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// @@ -875,7 +945,6 @@ public: class OpaqueValueExpr : public Expr { friend class ASTStmtReader; Expr *SourceExpr; - SourceLocation Loc; public: OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, @@ -889,8 +958,9 @@ public: T->isInstantiationDependentType() || (SourceExpr && SourceExpr->isInstantiationDependent()), false), - SourceExpr(SourceExpr), Loc(Loc) { + SourceExpr(SourceExpr) { setIsUnique(false); + OpaqueValueExprBits.Loc = Loc; } /// Given an expression which invokes a copy constructor --- i.e. a @@ -899,20 +969,19 @@ public: static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr); explicit OpaqueValueExpr(EmptyShell Empty) - : Expr(OpaqueValueExprClass, Empty) { } + : Expr(OpaqueValueExprClass, Empty) {} /// Retrieve the location of this expression. - SourceLocation getLocation() const { return Loc; } + SourceLocation getLocation() const { return OpaqueValueExprBits.Loc; } - SourceLocation getLocStart() const LLVM_READONLY { - return SourceExpr ? SourceExpr->getLocStart() : Loc; + SourceLocation getBeginLoc() const LLVM_READONLY { + return SourceExpr ? SourceExpr->getBeginLoc() : getLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return SourceExpr ? SourceExpr->getLocEnd() : Loc; + SourceLocation getEndLoc() const LLVM_READONLY { + return SourceExpr ? SourceExpr->getEndLoc() : getLocation(); } SourceLocation getExprLoc() const LLVM_READONLY { - if (SourceExpr) return SourceExpr->getExprLoc(); - return Loc; + return SourceExpr ? SourceExpr->getExprLoc() : getLocation(); } child_range children() { @@ -974,63 +1043,52 @@ class DeclRefExpr final private llvm::TrailingObjects<DeclRefExpr, NestedNameSpecifierLoc, NamedDecl *, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + /// The declaration that we are referencing. ValueDecl *D; - /// The location of the declaration name itself. - SourceLocation Loc; - /// Provides source/type location info for the declaration name /// embedded in D. DeclarationNameLoc DNLoc; size_t numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const { - return hasQualifier() ? 1 : 0; + return hasQualifier(); } size_t numTrailingObjects(OverloadToken<NamedDecl *>) const { - return hasFoundDecl() ? 1 : 0; + return hasFoundDecl(); } size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { - return hasTemplateKWAndArgsInfo() ? 1 : 0; + return hasTemplateKWAndArgsInfo(); } /// Test whether there is a distinct FoundDecl attached to the end of /// this DRE. bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; } - DeclRefExpr(const ASTContext &Ctx, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - ValueDecl *D, bool RefersToEnlosingVariableOrCapture, - const DeclarationNameInfo &NameInfo, - NamedDecl *FoundD, - const TemplateArgumentListInfo *TemplateArgs, - QualType T, ExprValueKind VK); + DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, ValueDecl *D, + bool RefersToEnlosingVariableOrCapture, + const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, + const TemplateArgumentListInfo *TemplateArgs, QualType T, + ExprValueKind VK); /// Construct an empty declaration reference expression. - explicit DeclRefExpr(EmptyShell Empty) - : Expr(DeclRefExprClass, Empty) { } + explicit DeclRefExpr(EmptyShell Empty) : Expr(DeclRefExprClass, Empty) {} /// Computes the type- and value-dependence flags for this /// declaration reference expression. - void computeDependence(const ASTContext &C); + void computeDependence(const ASTContext &Ctx); public: - DeclRefExpr(ValueDecl *D, bool RefersToEnclosingVariableOrCapture, QualType T, + DeclRefExpr(const ASTContext &Ctx, ValueDecl *D, + bool RefersToEnclosingVariableOrCapture, QualType T, ExprValueKind VK, SourceLocation L, - const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) - : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), - D(D), Loc(L), DNLoc(LocInfo) { - DeclRefExprBits.HasQualifier = 0; - DeclRefExprBits.HasTemplateKWAndArgsInfo = 0; - DeclRefExprBits.HasFoundDecl = 0; - DeclRefExprBits.HadMultipleCandidates = 0; - DeclRefExprBits.RefersToEnclosingVariableOrCapture = - RefersToEnclosingVariableOrCapture; - computeDependence(D->getASTContext()); - } + const DeclarationNameLoc &LocInfo = DeclarationNameLoc()); static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, @@ -1048,8 +1106,7 @@ public: const TemplateArgumentListInfo *TemplateArgs = nullptr); /// Construct an empty declaration reference expression. - static DeclRefExpr *CreateEmpty(const ASTContext &Context, - bool HasQualifier, + static DeclRefExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier, bool HasFoundDecl, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs); @@ -1059,13 +1116,13 @@ public: void setDecl(ValueDecl *NewD) { D = NewD; } DeclarationNameInfo getNameInfo() const { - return DeclarationNameInfo(getDecl()->getDeclName(), Loc, DNLoc); + return DeclarationNameInfo(getDecl()->getDeclName(), getLocation(), DNLoc); } - SourceLocation getLocation() const { return Loc; } - void setLocation(SourceLocation L) { Loc = L; } - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getLocation() const { return DeclRefExprBits.Loc; } + void setLocation(SourceLocation L) { DeclRefExprBits.Loc = L; } + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; /// Determine whether this declaration reference was preceded by a /// C++ nested-name-specifier, e.g., \c N::foo. @@ -1108,21 +1165,24 @@ public: /// Retrieve the location of the template keyword preceding /// this name, if any. SourceLocation getTemplateKeywordLoc() const { - if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the name, if any. SourceLocation getLAngleLoc() const { - if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the name, if any. SourceLocation getRAngleLoc() const { - if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc; } @@ -1147,7 +1207,6 @@ public: const TemplateArgumentLoc *getTemplateArgs() const { if (!hasExplicitTemplateArgs()) return nullptr; - return getTrailingObjects<TemplateArgumentLoc>(); } @@ -1156,7 +1215,6 @@ public: unsigned getNumTemplateArgs() const { if (!hasExplicitTemplateArgs()) return 0; - return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs; } @@ -1194,68 +1252,6 @@ public: const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } - - friend TrailingObjects; - friend class ASTStmtReader; - friend class ASTStmtWriter; -}; - -/// [C99 6.4.2.2] - A predefined identifier such as __func__. -class PredefinedExpr : public Expr { -public: - enum IdentType { - Func, - Function, - LFunction, // Same as Function, but as wide string. - FuncDName, - FuncSig, - LFuncSig, // Same as FuncSig, but as as wide string - PrettyFunction, - /// The same as PrettyFunction, except that the - /// 'virtual' keyword is omitted for virtual member functions. - PrettyFunctionNoVirtual - }; - -private: - SourceLocation Loc; - IdentType Type; - Stmt *FnName; - -public: - PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT, - StringLiteral *SL); - - /// Construct an empty predefined expression. - explicit PredefinedExpr(EmptyShell Empty) - : Expr(PredefinedExprClass, Empty), Loc(), Type(Func), FnName(nullptr) {} - - IdentType getIdentType() const { return Type; } - - SourceLocation getLocation() const { return Loc; } - void setLocation(SourceLocation L) { Loc = L; } - - StringLiteral *getFunctionName(); - const StringLiteral *getFunctionName() const { - return const_cast<PredefinedExpr *>(this)->getFunctionName(); - } - - static StringRef getIdentTypeName(IdentType IT); - static std::string ComputeName(IdentType IT, const Decl *CurrentDecl); - - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == PredefinedExprClass; - } - - // Iterators - child_range children() { return child_range(&FnName, &FnName + 1); } - const_child_range children() const { - return const_child_range(&FnName, &FnName + 1); - } - - friend class ASTStmtReader; }; /// Used by IntegerLiteral/FloatingLiteral to store the numeric without @@ -1331,8 +1327,8 @@ public: /// Returns a new empty integer literal. static IntegerLiteral *Create(const ASTContext &C, EmptyShell Empty); - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } /// Retrieve the location of the literal. SourceLocation getLocation() const { return Loc; } @@ -1370,8 +1366,8 @@ class FixedPointLiteral : public Expr, public APIntStorage { QualType type, SourceLocation l, unsigned Scale); - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } /// \brief Retrieve the location of the literal. SourceLocation getLocation() const { return Loc; } @@ -1424,8 +1420,8 @@ public: return static_cast<CharacterKind>(CharacterLiteralBits.Kind); } - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } unsigned getValue() const { return Value; } @@ -1497,8 +1493,8 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } static bool classof(const Stmt *T) { return T->getStmtClass() == FloatingLiteralClass; @@ -1534,8 +1530,10 @@ public: Expr *getSubExpr() { return cast<Expr>(Val); } void setSubExpr(Expr *E) { Val = E; } - SourceLocation getLocStart() const LLVM_READONLY { return Val->getLocStart(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Val->getLocEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { + return Val->getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY { return Val->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ImaginaryLiteralClass; @@ -1549,14 +1547,15 @@ public: }; /// StringLiteral - This represents a string literal expression, e.g. "foo" -/// or L"bar" (wide strings). The actual string is returned by getBytes() -/// is NOT null-terminated, and the length of the string is determined by -/// calling getByteLength(). The C type for a string is always a -/// ConstantArrayType. In C++, the char type is const qualified, in C it is -/// not. +/// or L"bar" (wide strings). The actual string data can be obtained with +/// getBytes() and is NOT null-terminated. The length of the string data is +/// determined by calling getByteLength(). +/// +/// The C type for a string is always a ConstantArrayType. In C++, the char +/// type is const qualified, in C it is not. /// /// Note that strings in C can be formed by concatenation of multiple string -/// literal pptokens in translation phase #6. This keeps track of the locations +/// literal pptokens in translation phase #6. This keeps track of the locations /// of each of these pieces. /// /// Strings in C can also be truncated and extended by assigning into arrays, @@ -1564,131 +1563,156 @@ public: /// char X[2] = "foobar"; /// In this case, getByteLength() will return 6, but the string literal will /// have type "char[2]". -class StringLiteral : public Expr { +class StringLiteral final + : public Expr, + private llvm::TrailingObjects<StringLiteral, unsigned, SourceLocation, + char> { + friend class ASTStmtReader; + friend TrailingObjects; + + /// StringLiteral is followed by several trailing objects. They are in order: + /// + /// * A single unsigned storing the length in characters of this string. The + /// length in bytes is this length times the width of a single character. + /// Always present and stored as a trailing objects because storing it in + /// StringLiteral would increase the size of StringLiteral by sizeof(void *) + /// due to alignment requirements. If you add some data to StringLiteral, + /// consider moving it inside StringLiteral. + /// + /// * An array of getNumConcatenated() SourceLocation, one for each of the + /// token this string is made of. + /// + /// * An array of getByteLength() char used to store the string data. + public: - enum StringKind { - Ascii, - Wide, - UTF8, - UTF16, - UTF32 - }; + enum StringKind { Ascii, Wide, UTF8, UTF16, UTF32 }; private: - friend class ASTStmtReader; + unsigned numTrailingObjects(OverloadToken<unsigned>) const { return 1; } + unsigned numTrailingObjects(OverloadToken<SourceLocation>) const { + return getNumConcatenated(); + } - union { - const char *asChar; - const uint16_t *asUInt16; - const uint32_t *asUInt32; - } StrData; - unsigned Length; - unsigned CharByteWidth : 4; - unsigned Kind : 3; - unsigned IsPascal : 1; - unsigned NumConcatenated; - SourceLocation TokLocs[1]; + unsigned numTrailingObjects(OverloadToken<char>) const { + return getByteLength(); + } + + char *getStrDataAsChar() { return getTrailingObjects<char>(); } + const char *getStrDataAsChar() const { return getTrailingObjects<char>(); } - StringLiteral(QualType Ty) : - Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false, - false) {} + const uint16_t *getStrDataAsUInt16() const { + return reinterpret_cast<const uint16_t *>(getTrailingObjects<char>()); + } + + const uint32_t *getStrDataAsUInt32() const { + return reinterpret_cast<const uint32_t *>(getTrailingObjects<char>()); + } + + /// Build a string literal. + StringLiteral(const ASTContext &Ctx, StringRef Str, StringKind Kind, + bool Pascal, QualType Ty, const SourceLocation *Loc, + unsigned NumConcatenated); + + /// Build an empty string literal. + StringLiteral(EmptyShell Empty, unsigned NumConcatenated, unsigned Length, + unsigned CharByteWidth); - static int mapCharByteWidth(TargetInfo const &target,StringKind k); + /// Map a target and string kind to the appropriate character width. + static unsigned mapCharByteWidth(TargetInfo const &Target, StringKind SK); + + /// Set one of the string literal token. + void setStrTokenLoc(unsigned TokNum, SourceLocation L) { + assert(TokNum < getNumConcatenated() && "Invalid tok number"); + getTrailingObjects<SourceLocation>()[TokNum] = L; + } public: /// This is the "fully general" constructor that allows representation of /// strings formed from multiple concatenated tokens. - static StringLiteral *Create(const ASTContext &C, StringRef Str, + static StringLiteral *Create(const ASTContext &Ctx, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, - const SourceLocation *Loc, unsigned NumStrs); + const SourceLocation *Loc, + unsigned NumConcatenated); /// Simple constructor for string literals made from one token. - static StringLiteral *Create(const ASTContext &C, StringRef Str, + static StringLiteral *Create(const ASTContext &Ctx, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, SourceLocation Loc) { - return Create(C, Str, Kind, Pascal, Ty, &Loc, 1); + return Create(Ctx, Str, Kind, Pascal, Ty, &Loc, 1); } /// Construct an empty string literal. - static StringLiteral *CreateEmpty(const ASTContext &C, unsigned NumStrs); + static StringLiteral *CreateEmpty(const ASTContext &Ctx, + unsigned NumConcatenated, unsigned Length, + unsigned CharByteWidth); StringRef getString() const { - assert(CharByteWidth==1 - && "This function is used in places that assume strings use char"); - return StringRef(StrData.asChar, getByteLength()); + assert(getCharByteWidth() == 1 && + "This function is used in places that assume strings use char"); + return StringRef(getStrDataAsChar(), getByteLength()); } /// Allow access to clients that need the byte representation, such as /// ASTWriterStmt::VisitStringLiteral(). StringRef getBytes() const { // FIXME: StringRef may not be the right type to use as a result for this. - if (CharByteWidth == 1) - return StringRef(StrData.asChar, getByteLength()); - if (CharByteWidth == 4) - return StringRef(reinterpret_cast<const char*>(StrData.asUInt32), - getByteLength()); - assert(CharByteWidth == 2 && "unsupported CharByteWidth"); - return StringRef(reinterpret_cast<const char*>(StrData.asUInt16), - getByteLength()); + return StringRef(getStrDataAsChar(), getByteLength()); } void outputString(raw_ostream &OS) const; uint32_t getCodeUnit(size_t i) const { - assert(i < Length && "out of bounds access"); - if (CharByteWidth == 1) - return static_cast<unsigned char>(StrData.asChar[i]); - if (CharByteWidth == 4) - return StrData.asUInt32[i]; - assert(CharByteWidth == 2 && "unsupported CharByteWidth"); - return StrData.asUInt16[i]; + assert(i < getLength() && "out of bounds access"); + switch (getCharByteWidth()) { + case 1: + return static_cast<unsigned char>(getStrDataAsChar()[i]); + case 2: + return getStrDataAsUInt16()[i]; + case 4: + return getStrDataAsUInt32()[i]; + } + llvm_unreachable("Unsupported character width!"); } - unsigned getByteLength() const { return CharByteWidth*Length; } - unsigned getLength() const { return Length; } - unsigned getCharByteWidth() const { return CharByteWidth; } - - /// Sets the string data to the given string data. - void setString(const ASTContext &C, StringRef Str, - StringKind Kind, bool IsPascal); - - StringKind getKind() const { return static_cast<StringKind>(Kind); } + unsigned getByteLength() const { return getCharByteWidth() * getLength(); } + unsigned getLength() const { return *getTrailingObjects<unsigned>(); } + unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; } + StringKind getKind() const { + return static_cast<StringKind>(StringLiteralBits.Kind); + } - bool isAscii() const { return Kind == Ascii; } - bool isWide() const { return Kind == Wide; } - bool isUTF8() const { return Kind == UTF8; } - bool isUTF16() const { return Kind == UTF16; } - bool isUTF32() const { return Kind == UTF32; } - bool isPascal() const { return IsPascal; } + bool isAscii() const { return getKind() == Ascii; } + bool isWide() const { return getKind() == Wide; } + bool isUTF8() const { return getKind() == UTF8; } + bool isUTF16() const { return getKind() == UTF16; } + bool isUTF32() const { return getKind() == UTF32; } + bool isPascal() const { return StringLiteralBits.IsPascal; } bool containsNonAscii() const { - StringRef Str = getString(); - for (unsigned i = 0, e = Str.size(); i != e; ++i) - if (!isASCII(Str[i])) + for (auto c : getString()) + if (!isASCII(c)) return true; return false; } bool containsNonAsciiOrNull() const { - StringRef Str = getString(); - for (unsigned i = 0, e = Str.size(); i != e; ++i) - if (!isASCII(Str[i]) || !Str[i]) + for (auto c : getString()) + if (!isASCII(c) || !c) return true; return false; } /// getNumConcatenated - Get the number of string literal tokens that were /// concatenated in translation phase #6 to form this string literal. - unsigned getNumConcatenated() const { return NumConcatenated; } + unsigned getNumConcatenated() const { + return StringLiteralBits.NumConcatenated; + } + /// Get one of the string literal token. SourceLocation getStrTokenLoc(unsigned TokNum) const { - assert(TokNum < NumConcatenated && "Invalid tok number"); - return TokLocs[TokNum]; - } - void setStrTokenLoc(unsigned TokNum, SourceLocation L) { - assert(TokNum < NumConcatenated && "Invalid tok number"); - TokLocs[TokNum] = L; + assert(TokNum < getNumConcatenated() && "Invalid tok number"); + return getTrailingObjects<SourceLocation>()[TokNum]; } /// getLocationOfByte - Return a source location that points to the specified @@ -1705,14 +1729,18 @@ public: unsigned *StartTokenByteOffset = nullptr) const; typedef const SourceLocation *tokloc_iterator; - tokloc_iterator tokloc_begin() const { return TokLocs; } - tokloc_iterator tokloc_end() const { return TokLocs + NumConcatenated; } - SourceLocation getLocStart() const LLVM_READONLY { return TokLocs[0]; } - SourceLocation getLocEnd() const LLVM_READONLY { - return TokLocs[NumConcatenated - 1]; + tokloc_iterator tokloc_begin() const { + return getTrailingObjects<SourceLocation>(); } + tokloc_iterator tokloc_end() const { + return getTrailingObjects<SourceLocation>() + getNumConcatenated(); + } + + SourceLocation getBeginLoc() const LLVM_READONLY { return *tokloc_begin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return *(tokloc_end() - 1); } + static bool classof(const Stmt *T) { return T->getStmtClass() == StringLiteralClass; } @@ -1726,6 +1754,91 @@ public: } }; +/// [C99 6.4.2.2] - A predefined identifier such as __func__. +class PredefinedExpr final + : public Expr, + private llvm::TrailingObjects<PredefinedExpr, Stmt *> { + friend class ASTStmtReader; + friend TrailingObjects; + + // PredefinedExpr is optionally followed by a single trailing + // "Stmt *" for the predefined identifier. It is present if and only if + // hasFunctionName() is true and is always a "StringLiteral *". + +public: + enum IdentKind { + Func, + Function, + LFunction, // Same as Function, but as wide string. + FuncDName, + FuncSig, + LFuncSig, // Same as FuncSig, but as as wide string + PrettyFunction, + /// The same as PrettyFunction, except that the + /// 'virtual' keyword is omitted for virtual member functions. + PrettyFunctionNoVirtual + }; + +private: + PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, + StringLiteral *SL); + + explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName); + + /// True if this PredefinedExpr has storage for a function name. + bool hasFunctionName() const { return PredefinedExprBits.HasFunctionName; } + + void setFunctionName(StringLiteral *SL) { + assert(hasFunctionName() && + "This PredefinedExpr has no storage for a function name!"); + *getTrailingObjects<Stmt *>() = SL; + } + +public: + /// Create a PredefinedExpr. + static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, + QualType FNTy, IdentKind IK, StringLiteral *SL); + + /// Create an empty PredefinedExpr. + static PredefinedExpr *CreateEmpty(const ASTContext &Ctx, + bool HasFunctionName); + + IdentKind getIdentKind() const { + return static_cast<IdentKind>(PredefinedExprBits.Kind); + } + + SourceLocation getLocation() const { return PredefinedExprBits.Loc; } + void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; } + + StringLiteral *getFunctionName() { + return hasFunctionName() + ? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>()) + : nullptr; + } + + const StringLiteral *getFunctionName() const { + return hasFunctionName() + ? static_cast<StringLiteral *>(*getTrailingObjects<Stmt *>()) + : nullptr; + } + + static StringRef getIdentKindName(IdentKind IK); + static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl); + + SourceLocation getBeginLoc() const { return getLocation(); } + SourceLocation getEndLoc() const { return getLocation(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PredefinedExprClass; + } + + // Iterators + child_range children() { + return child_range(getTrailingObjects<Stmt *>(), + getTrailingObjects<Stmt *>() + hasFunctionName()); + } +}; + /// ParenExpr - This represents a parethesized expression, e.g. "(1)". This /// AST node is only formed if full location information is requested. class ParenExpr : public Expr { @@ -1748,8 +1861,8 @@ public: Expr *getSubExpr() { return cast<Expr>(Val); } void setSubExpr(Expr *E) { Val = E; } - SourceLocation getLocStart() const LLVM_READONLY { return L; } - SourceLocation getLocEnd() const LLVM_READONLY { return R; } + SourceLocation getBeginLoc() const LLVM_READONLY { return L; } + SourceLocation getEndLoc() const LLVM_READONLY { return R; } /// Get the location of the left parentheses '('. SourceLocation getLParen() const { return L; } @@ -1781,15 +1894,11 @@ public: /// later returns zero in the type of the operand. /// class UnaryOperator : public Expr { + Stmt *Val; + public: typedef UnaryOperatorKind Opcode; -private: - unsigned Opc : 5; - unsigned CanOverflow : 1; - SourceLocation Loc; - Stmt *Val; -public: UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, bool CanOverflow) : Expr(UnaryOperatorClass, type, VK, OK, @@ -1798,21 +1907,28 @@ public: (input->isInstantiationDependent() || type->isInstantiationDependentType()), input->containsUnexpandedParameterPack()), - Opc(opc), CanOverflow(CanOverflow), Loc(l), Val(input) {} + Val(input) { + UnaryOperatorBits.Opc = opc; + UnaryOperatorBits.CanOverflow = CanOverflow; + UnaryOperatorBits.Loc = l; + } /// Build an empty unary operator. - explicit UnaryOperator(EmptyShell Empty) - : Expr(UnaryOperatorClass, Empty), Opc(UO_AddrOf) { } + explicit UnaryOperator(EmptyShell Empty) : Expr(UnaryOperatorClass, Empty) { + UnaryOperatorBits.Opc = UO_AddrOf; + } - Opcode getOpcode() const { return static_cast<Opcode>(Opc); } - void setOpcode(Opcode O) { Opc = O; } + Opcode getOpcode() const { + return static_cast<Opcode>(UnaryOperatorBits.Opc); + } + void setOpcode(Opcode Opc) { UnaryOperatorBits.Opc = Opc; } Expr *getSubExpr() const { return cast<Expr>(Val); } void setSubExpr(Expr *E) { Val = E; } /// getOperatorLoc - Return the location of the operator. - SourceLocation getOperatorLoc() const { return Loc; } - void setOperatorLoc(SourceLocation L) { Loc = L; } + SourceLocation getOperatorLoc() const { return UnaryOperatorBits.Loc; } + void setOperatorLoc(SourceLocation L) { UnaryOperatorBits.Loc = L; } /// Returns true if the unary operator can cause an overflow. For instance, /// signed int i = INT_MAX; i++; @@ -1820,8 +1936,8 @@ public: /// Due to integer promotions, c++ is promoted to an int before the postfix /// increment, and the result is an int that cannot overflow. However, i++ /// can overflow. - bool canOverflow() const { return CanOverflow; } - void setCanOverflow(bool C) { CanOverflow = C; } + bool canOverflow() const { return UnaryOperatorBits.CanOverflow; } + void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; } /// isPostfix - Return true if this is a postfix operation, like x++. static bool isPostfix(Opcode Op) { @@ -1872,13 +1988,13 @@ public: /// the given unary opcode. static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); - SourceLocation getLocStart() const LLVM_READONLY { - return isPostfix() ? Val->getLocStart() : Loc; + SourceLocation getBeginLoc() const LLVM_READONLY { + return isPostfix() ? Val->getBeginLoc() : getOperatorLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return isPostfix() ? Loc : Val->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return isPostfix() ? getOperatorLoc() : Val->getEndLoc(); } - SourceLocation getExprLoc() const LLVM_READONLY { return Loc; } + SourceLocation getExprLoc() const { return getOperatorLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryOperatorClass; @@ -1980,8 +2096,8 @@ public: /// contains the location of the period (if there is one) and the /// identifier. SourceRange getSourceRange() const LLVM_READONLY { return Range; } - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } }; /// OffsetOfExpr - [C99 7.17] - This represents an expression of the form @@ -2080,8 +2196,8 @@ public: return NumExprs; } - SourceLocation getLocStart() const LLVM_READONLY { return OperatorLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return OperatorLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == OffsetOfExprClass; @@ -2176,8 +2292,8 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return OpLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return OpLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryExprOrTypeTraitExprClass; @@ -2194,9 +2310,11 @@ public: /// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting. class ArraySubscriptExpr : public Expr { - enum { LHS, RHS, END_EXPR=2 }; - Stmt* SubExprs[END_EXPR]; - SourceLocation RBracketLoc; + enum { LHS, RHS, END_EXPR }; + Stmt *SubExprs[END_EXPR]; + + bool lhsIsBase() const { return getRHS()->getType()->isIntegerType(); } + public: ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t, ExprValueKind VK, ExprObjectKind OK, @@ -2207,10 +2325,10 @@ public: (lhs->isInstantiationDependent() || rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || - rhs->containsUnexpandedParameterPack())), - RBracketLoc(rbracketloc) { + rhs->containsUnexpandedParameterPack())) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; + ArraySubscriptExprBits.RBracketLoc = rbracketloc; } /// Create an empty array subscript expression. @@ -2234,29 +2352,23 @@ public: const Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } - Expr *getBase() { - return getRHS()->getType()->isIntegerType() ? getLHS() : getRHS(); - } + Expr *getBase() { return lhsIsBase() ? getLHS() : getRHS(); } + const Expr *getBase() const { return lhsIsBase() ? getLHS() : getRHS(); } - const Expr *getBase() const { - return getRHS()->getType()->isIntegerType() ? getLHS() : getRHS(); - } + Expr *getIdx() { return lhsIsBase() ? getRHS() : getLHS(); } + const Expr *getIdx() const { return lhsIsBase() ? getRHS() : getLHS(); } - Expr *getIdx() { - return getRHS()->getType()->isIntegerType() ? getRHS() : getLHS(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getLHS()->getBeginLoc(); } + SourceLocation getEndLoc() const { return getRBracketLoc(); } - const Expr *getIdx() const { - return getRHS()->getType()->isIntegerType() ? getRHS() : getLHS(); + SourceLocation getRBracketLoc() const { + return ArraySubscriptExprBits.RBracketLoc; } - - SourceLocation getLocStart() const LLVM_READONLY { - return getLHS()->getLocStart(); + void setRBracketLoc(SourceLocation L) { + ArraySubscriptExprBits.RBracketLoc = L; } - SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; } - - SourceLocation getRBracketLoc() const { return RBracketLoc; } - void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } SourceLocation getExprLoc() const LLVM_READONLY { return getBase()->getExprLoc(); @@ -2282,127 +2394,221 @@ public: /// a subclass for overloaded operator calls that use operator syntax, e.g., /// "str1 + str2" to resolve to a function call. class CallExpr : public Expr { - enum { FN=0, PREARGS_START=1 }; - Stmt **SubExprs; + enum { FN = 0, PREARGS_START = 1 }; + + /// The number of arguments in the call expression. unsigned NumArgs; + + /// The location of the right parenthese. This has a different meaning for + /// the derived classes of CallExpr. SourceLocation RParenLoc; void updateDependenciesFromArg(Expr *Arg); + // CallExpr store some data in trailing objects. However since CallExpr + // is used a base of other expression classes we cannot use + // llvm::TrailingObjects. Instead we manually perform the pointer arithmetic + // and casts. + // + // The trailing objects are in order: + // + // * A single "Stmt *" for the callee expression. + // + // * An array of getNumPreArgs() "Stmt *" for the pre-argument expressions. + // + // * An array of getNumArgs() "Stmt *" for the argument expressions. + // + // Note that we store the offset in bytes from the this pointer to the start + // of the trailing objects. It would be perfectly possible to compute it + // based on the dynamic kind of the CallExpr. However 1.) we have plenty of + // space in the bit-fields of Stmt. 2.) It was benchmarked to be faster to + // compute this once and then load the offset from the bit-fields of Stmt, + // instead of re-computing the offset each time the trailing objects are + // accessed. + + /// Return a pointer to the start of the trailing array of "Stmt *". + Stmt **getTrailingStmts() { + return reinterpret_cast<Stmt **>(reinterpret_cast<char *>(this) + + CallExprBits.OffsetToTrailingObjects); + } + Stmt *const *getTrailingStmts() const { + return const_cast<CallExpr *>(this)->getTrailingStmts(); + } + + /// Map a statement class to the appropriate offset in bytes from the + /// this pointer to the trailing objects. + static unsigned offsetToTrailingObjects(StmtClass SC); + +public: + enum class ADLCallKind : bool { NotADL, UsesADL }; + static constexpr ADLCallKind NotADL = ADLCallKind::NotADL; + static constexpr ADLCallKind UsesADL = ADLCallKind::UsesADL; + protected: - // These versions of the constructor are for derived classes. - CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, - ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t, - ExprValueKind VK, SourceLocation rparenloc); - CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> args, - QualType t, ExprValueKind VK, SourceLocation rparenloc); - CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs, + /// Build a call expression, assuming that appropriate storage has been + /// allocated for the trailing objects. + CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs, + ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK, + SourceLocation RParenLoc, unsigned MinNumArgs, ADLCallKind UsesADL); + + /// Build an empty call expression, for deserialization. + CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs, EmptyShell Empty); - Stmt *getPreArg(unsigned i) { - assert(i < getNumPreArgs() && "Prearg access out of range!"); - return SubExprs[PREARGS_START+i]; + /// Return the size in bytes needed for the trailing objects. + /// Used by the derived classes to allocate the right amount of storage. + static unsigned sizeOfTrailingObjects(unsigned NumPreArgs, unsigned NumArgs) { + return (1 + NumPreArgs + NumArgs) * sizeof(Stmt *); } - const Stmt *getPreArg(unsigned i) const { - assert(i < getNumPreArgs() && "Prearg access out of range!"); - return SubExprs[PREARGS_START+i]; + + Stmt *getPreArg(unsigned I) { + assert(I < getNumPreArgs() && "Prearg access out of range!"); + return getTrailingStmts()[PREARGS_START + I]; + } + const Stmt *getPreArg(unsigned I) const { + assert(I < getNumPreArgs() && "Prearg access out of range!"); + return getTrailingStmts()[PREARGS_START + I]; } - void setPreArg(unsigned i, Stmt *PreArg) { - assert(i < getNumPreArgs() && "Prearg access out of range!"); - SubExprs[PREARGS_START+i] = PreArg; + void setPreArg(unsigned I, Stmt *PreArg) { + assert(I < getNumPreArgs() && "Prearg access out of range!"); + getTrailingStmts()[PREARGS_START + I] = PreArg; } unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; } public: - CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t, - ExprValueKind VK, SourceLocation rparenloc); + /// Create a call expression. Fn is the callee expression, Args is the + /// argument array, Ty is the type of the call expression (which is *not* + /// the return type in general), VK is the value kind of the call expression + /// (lvalue, rvalue, ...), and RParenLoc is the location of the right + /// parenthese in the call expression. MinNumArgs specifies the minimum + /// number of arguments. The actual number of arguments will be the greater + /// of Args.size() and MinNumArgs. This is used in a few places to allocate + /// enough storage for the default arguments. UsesADL specifies whether the + /// callee was found through argument-dependent lookup. + /// + /// Note that you can use CreateTemporary if you need a temporary call + /// expression on the stack. + static CallExpr *Create(const ASTContext &Ctx, Expr *Fn, + ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK, + SourceLocation RParenLoc, unsigned MinNumArgs = 0, + ADLCallKind UsesADL = NotADL); - /// Build an empty call expression. - CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty); + /// Create a temporary call expression with no arguments in the memory + /// pointed to by Mem. Mem must points to at least sizeof(CallExpr) + /// + sizeof(Stmt *) bytes of storage, aligned to alignof(CallExpr): + /// + /// \code{.cpp} + /// llvm::AlignedCharArray<alignof(CallExpr), + /// sizeof(CallExpr) + sizeof(Stmt *)> Buffer; + /// CallExpr *TheCall = CallExpr::CreateTemporary(Buffer.buffer, etc); + /// \endcode + static CallExpr *CreateTemporary(void *Mem, Expr *Fn, QualType Ty, + ExprValueKind VK, SourceLocation RParenLoc, + ADLCallKind UsesADL = NotADL); - const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); } - Expr *getCallee() { return cast<Expr>(SubExprs[FN]); } - void setCallee(Expr *F) { SubExprs[FN] = F; } + /// Create an empty call expression, for deserialization. + static CallExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, + EmptyShell Empty); + + Expr *getCallee() { return cast<Expr>(getTrailingStmts()[FN]); } + const Expr *getCallee() const { return cast<Expr>(getTrailingStmts()[FN]); } + void setCallee(Expr *F) { getTrailingStmts()[FN] = F; } + + ADLCallKind getADLCallKind() const { + return static_cast<ADLCallKind>(CallExprBits.UsesADL); + } + void setADLCallKind(ADLCallKind V = UsesADL) { + CallExprBits.UsesADL = static_cast<bool>(V); + } + bool usesADL() const { return getADLCallKind() == UsesADL; } - Decl *getCalleeDecl(); + Decl *getCalleeDecl() { return getCallee()->getReferencedDeclOfCallee(); } const Decl *getCalleeDecl() const { - return const_cast<CallExpr*>(this)->getCalleeDecl(); + return getCallee()->getReferencedDeclOfCallee(); } - /// If the callee is a FunctionDecl, return it. Otherwise return 0. - FunctionDecl *getDirectCallee(); + /// If the callee is a FunctionDecl, return it. Otherwise return null. + FunctionDecl *getDirectCallee() { + return dyn_cast_or_null<FunctionDecl>(getCalleeDecl()); + } const FunctionDecl *getDirectCallee() const { - return const_cast<CallExpr*>(this)->getDirectCallee(); + return dyn_cast_or_null<FunctionDecl>(getCalleeDecl()); } /// getNumArgs - Return the number of actual arguments to this call. - /// unsigned getNumArgs() const { return NumArgs; } /// Retrieve the call arguments. Expr **getArgs() { - return reinterpret_cast<Expr **>(SubExprs+getNumPreArgs()+PREARGS_START); + return reinterpret_cast<Expr **>(getTrailingStmts() + PREARGS_START + + getNumPreArgs()); } const Expr *const *getArgs() const { - return reinterpret_cast<Expr **>(SubExprs + getNumPreArgs() + - PREARGS_START); + return reinterpret_cast<const Expr *const *>( + getTrailingStmts() + PREARGS_START + getNumPreArgs()); } /// getArg - Return the specified argument. Expr *getArg(unsigned Arg) { - assert(Arg < NumArgs && "Arg access out of range!"); - return cast_or_null<Expr>(SubExprs[Arg + getNumPreArgs() + PREARGS_START]); + assert(Arg < getNumArgs() && "Arg access out of range!"); + return getArgs()[Arg]; } const Expr *getArg(unsigned Arg) const { - assert(Arg < NumArgs && "Arg access out of range!"); - return cast_or_null<Expr>(SubExprs[Arg + getNumPreArgs() + PREARGS_START]); + assert(Arg < getNumArgs() && "Arg access out of range!"); + return getArgs()[Arg]; } /// setArg - Set the specified argument. void setArg(unsigned Arg, Expr *ArgExpr) { - assert(Arg < NumArgs && "Arg access out of range!"); - SubExprs[Arg+getNumPreArgs()+PREARGS_START] = ArgExpr; + assert(Arg < getNumArgs() && "Arg access out of range!"); + getArgs()[Arg] = ArgExpr; } - /// setNumArgs - This changes the number of arguments present in this call. - /// Any orphaned expressions are deleted by this, and any new operands are set - /// to null. - void setNumArgs(const ASTContext& C, unsigned NumArgs); + /// Reduce the number of arguments in this call expression. This is used for + /// example during error recovery to drop extra arguments. There is no way + /// to perform the opposite because: 1.) We don't track how much storage + /// we have for the argument array 2.) This would potentially require growing + /// the argument array, something we cannot support since the arguments are + /// stored in a trailing array. + void shrinkNumArgs(unsigned NewNumArgs) { + assert((NewNumArgs <= getNumArgs()) && + "shrinkNumArgs cannot increase the number of arguments!"); + NumArgs = NewNumArgs; + } typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; typedef llvm::iterator_range<arg_iterator> arg_range; - typedef llvm::iterator_range<const_arg_iterator> arg_const_range; + typedef llvm::iterator_range<const_arg_iterator> const_arg_range; arg_range arguments() { return arg_range(arg_begin(), arg_end()); } - arg_const_range arguments() const { - return arg_const_range(arg_begin(), arg_end()); + const_arg_range arguments() const { + return const_arg_range(arg_begin(), arg_end()); } - arg_iterator arg_begin() { return SubExprs+PREARGS_START+getNumPreArgs(); } - arg_iterator arg_end() { - return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs(); + arg_iterator arg_begin() { + return getTrailingStmts() + PREARGS_START + getNumPreArgs(); } + arg_iterator arg_end() { return arg_begin() + getNumArgs(); } + const_arg_iterator arg_begin() const { - return SubExprs+PREARGS_START+getNumPreArgs(); - } - const_arg_iterator arg_end() const { - return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs(); + return getTrailingStmts() + PREARGS_START + getNumPreArgs(); } + const_arg_iterator arg_end() const { return arg_begin() + getNumArgs(); } /// This method provides fast access to all the subexpressions of /// a CallExpr without going through the slower virtual child_iterator /// interface. This provides efficient reverse iteration of the /// subexpressions. This is currently used for CFG construction. - ArrayRef<Stmt*> getRawSubExprs() { - return llvm::makeArrayRef(SubExprs, - getNumPreArgs() + PREARGS_START + getNumArgs()); + ArrayRef<Stmt *> getRawSubExprs() { + return llvm::makeArrayRef(getTrailingStmts(), + PREARGS_START + getNumPreArgs() + getNumArgs()); } /// getNumCommas - Return the number of commas that must have been present in /// this function call. - unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; } + unsigned getNumCommas() const { return getNumArgs() ? getNumArgs() - 1 : 0; } /// getBuiltinCallee - If this is a call to a builtin, return the builtin ID /// of the callee. If not, return 0. @@ -2417,18 +2623,27 @@ public: /// type. QualType getCallReturnType(const ASTContext &Ctx) const; + /// Returns the WarnUnusedResultAttr that is either declared on the called + /// function, or its return type declaration. + const Attr *getUnusedResultAttr(const ASTContext &Ctx) const; + + /// Returns true if this call expression should warn on unused results. + bool hasUnusedResultAttr(const ASTContext &Ctx) const { + return getUnusedResultAttr(Ctx) != nullptr; + } + SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; /// Return true if this is a call to __assume() or __builtin_assume() with /// a non-value-dependent constant parameter evaluating as false. bool isBuiltinAssumeFalse(const ASTContext &Ctx) const; bool isCallToStdMove() const { - const FunctionDecl* FD = getDirectCallee(); + const FunctionDecl *FD = getDirectCallee(); return getNumArgs() == 1 && FD && FD->isInStdNamespace() && FD->getIdentifier() && FD->getIdentifier()->isStr("move"); } @@ -2440,13 +2655,14 @@ public: // Iterators child_range children() { - return child_range(&SubExprs[0], - &SubExprs[0]+NumArgs+getNumPreArgs()+PREARGS_START); + return child_range(getTrailingStmts(), getTrailingStmts() + PREARGS_START + + getNumPreArgs() + getNumArgs()); } const_child_range children() const { - return const_child_range(&SubExprs[0], &SubExprs[0] + NumArgs + - getNumPreArgs() + PREARGS_START); + return const_child_range(getTrailingStmts(), + getTrailingStmts() + PREARGS_START + + getNumPreArgs() + getNumArgs()); } }; @@ -2468,6 +2684,10 @@ class MemberExpr final private llvm::TrailingObjects<MemberExpr, MemberExprNameQualifier, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { + friend class ASTReader; + friend class ASTStmtWriter; + friend TrailingObjects; + /// Base - the expression for the base pointer or structure references. In /// X.F, this is "X". Stmt *Base; @@ -2483,35 +2703,20 @@ class MemberExpr final /// MemberLoc - This is the location of the member name. SourceLocation MemberLoc; - /// This is the location of the -> or . in the expression. - SourceLocation OperatorLoc; - - /// IsArrow - True if this is "X->F", false if this is "X.F". - bool IsArrow : 1; - - /// True if this member expression used a nested-name-specifier to - /// refer to the member, e.g., "x->Base::f", or found its member via a using - /// declaration. When true, a MemberExprNameQualifier - /// structure is allocated immediately after the MemberExpr. - bool HasQualifierOrFoundDecl : 1; - - /// True if this member expression specified a template keyword - /// and/or a template argument list explicitly, e.g., x->f<int>, - /// x->template f, x->template f<int>. - /// When true, an ASTTemplateKWAndArgsInfo structure and its - /// TemplateArguments (if any) are present. - bool HasTemplateKWAndArgsInfo : 1; - - /// True if this member expression refers to a method that - /// was resolved from an overloaded set having size greater than 1. - bool HadMultipleCandidates : 1; - size_t numTrailingObjects(OverloadToken<MemberExprNameQualifier>) const { - return HasQualifierOrFoundDecl ? 1 : 0; + return hasQualifierOrFoundDecl(); } size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { - return HasTemplateKWAndArgsInfo ? 1 : 0; + return hasTemplateKWAndArgsInfo(); + } + + bool hasQualifierOrFoundDecl() const { + return MemberExprBits.HasQualifierOrFoundDecl; + } + + bool hasTemplateKWAndArgsInfo() const { + return MemberExprBits.HasTemplateKWAndArgsInfo; } public: @@ -2522,10 +2727,13 @@ public: base->isValueDependent(), base->isInstantiationDependent(), base->containsUnexpandedParameterPack()), Base(base), MemberDecl(memberdecl), MemberDNLoc(NameInfo.getInfo()), - MemberLoc(NameInfo.getLoc()), OperatorLoc(operatorloc), - IsArrow(isarrow), HasQualifierOrFoundDecl(false), - HasTemplateKWAndArgsInfo(false), HadMultipleCandidates(false) { + MemberLoc(NameInfo.getLoc()) { assert(memberdecl->getDeclName() == NameInfo.getName()); + MemberExprBits.IsArrow = isarrow; + MemberExprBits.HasQualifierOrFoundDecl = false; + MemberExprBits.HasTemplateKWAndArgsInfo = false; + MemberExprBits.HadMultipleCandidates = false; + MemberExprBits.OperatorLoc = operatorloc; } // NOTE: this constructor should be used only when it is known that @@ -2538,10 +2746,13 @@ public: : Expr(MemberExprClass, ty, VK, OK, base->isTypeDependent(), base->isValueDependent(), base->isInstantiationDependent(), base->containsUnexpandedParameterPack()), - Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l), - OperatorLoc(operatorloc), IsArrow(isarrow), - HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false), - HadMultipleCandidates(false) {} + Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l) { + MemberExprBits.IsArrow = isarrow; + MemberExprBits.HasQualifierOrFoundDecl = false; + MemberExprBits.HasTemplateKWAndArgsInfo = false; + MemberExprBits.HadMultipleCandidates = false; + MemberExprBits.OperatorLoc = operatorloc; + } static MemberExpr *Create(const ASTContext &C, Expr *base, bool isarrow, SourceLocation OperatorLoc, @@ -2564,7 +2775,7 @@ public: /// Retrieves the declaration found by lookup. DeclAccessPair getFoundDecl() const { - if (!HasQualifierOrFoundDecl) + if (!hasQualifierOrFoundDecl()) return DeclAccessPair::make(getMemberDecl(), getMemberDecl()->getAccess()); return getTrailingObjects<MemberExprNameQualifier>()->FoundDecl; @@ -2579,9 +2790,8 @@ public: /// nested-name-specifier that precedes the member name, with source-location /// information. NestedNameSpecifierLoc getQualifierLoc() const { - if (!HasQualifierOrFoundDecl) + if (!hasQualifierOrFoundDecl()) return NestedNameSpecifierLoc(); - return getTrailingObjects<MemberExprNameQualifier>()->QualifierLoc; } @@ -2595,21 +2805,24 @@ public: /// Retrieve the location of the template keyword preceding /// the member name, if any. SourceLocation getTemplateKeywordLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the member name, if any. SourceLocation getLAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the member name, if any. SourceLocation getRAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc; } @@ -2656,18 +2869,18 @@ public: MemberLoc, MemberDNLoc); } - SourceLocation getOperatorLoc() const LLVM_READONLY { return OperatorLoc; } + SourceLocation getOperatorLoc() const { return MemberExprBits.OperatorLoc; } - bool isArrow() const { return IsArrow; } - void setArrow(bool A) { IsArrow = A; } + bool isArrow() const { return MemberExprBits.IsArrow; } + void setArrow(bool A) { MemberExprBits.IsArrow = A; } /// getMemberLoc - Return the location of the "member", in X->F, it is the /// location of 'F'. SourceLocation getMemberLoc() const { return MemberLoc; } void setMemberLoc(SourceLocation L) { MemberLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; SourceLocation getExprLoc() const LLVM_READONLY { return MemberLoc; } @@ -2679,13 +2892,13 @@ public: /// Returns true if this member expression refers to a method that /// was resolved from an overloaded set having size greater than 1. bool hadMultipleCandidates() const { - return HadMultipleCandidates; + return MemberExprBits.HadMultipleCandidates; } /// Sets the flag telling whether this expression refers to /// a method that was resolved from an overloaded set having size /// greater than 1. void setHadMultipleCandidates(bool V = true) { - HadMultipleCandidates = V; + MemberExprBits.HadMultipleCandidates = V; } /// Returns true if virtual dispatch is performed. @@ -2705,10 +2918,6 @@ public: const_child_range children() const { return const_child_range(&Base, &Base + 1); } - - friend TrailingObjects; - friend class ASTReader; - friend class ASTStmtWriter; }; /// CompoundLiteralExpr - [C99 6.5.2.5] @@ -2756,19 +2965,19 @@ public: TInfoAndScope.setPointer(tinfo); } - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getBeginLoc() const LLVM_READONLY { // FIXME: Init should never be null. if (!Init) return SourceLocation(); if (LParenLoc.isInvalid()) - return Init->getLocStart(); + return Init->getBeginLoc(); return LParenLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { // FIXME: Init should never be null. if (!Init) return SourceLocation(); - return Init->getLocEnd(); + return Init->getEndLoc(); } static bool classof(const Stmt *T) { @@ -2787,28 +2996,15 @@ public: /// representation in the source code (ExplicitCastExpr's derived /// classes). class CastExpr : public Expr { -public: - using BasePathSizeTy = unsigned int; - static_assert(std::numeric_limits<BasePathSizeTy>::max() >= 16384, - "[implimits] Direct and indirect base classes [16384]."); - -private: Stmt *Op; bool CastConsistency() const; - BasePathSizeTy *BasePathSize(); - const CXXBaseSpecifier * const *path_buffer() const { return const_cast<CastExpr*>(this)->path_buffer(); } CXXBaseSpecifier **path_buffer(); - void setBasePathSize(BasePathSizeTy basePathSize) { - assert(!path_empty() && basePathSize != 0); - *(BasePathSize()) = basePathSize; - } - protected: CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, const CastKind kind, Expr *op, unsigned BasePathSize) @@ -2829,9 +3025,9 @@ protected: Op(op) { CastExprBits.Kind = kind; CastExprBits.PartOfExplicitCast = false; - CastExprBits.BasePathIsEmpty = BasePathSize == 0; - if (!path_empty()) - setBasePathSize(BasePathSize); + CastExprBits.BasePathSize = BasePathSize; + assert((CastExprBits.BasePathSize == BasePathSize) && + "BasePathSize overflow!"); assert(CastConsistency()); } @@ -2839,9 +3035,9 @@ protected: CastExpr(StmtClass SC, EmptyShell Empty, unsigned BasePathSize) : Expr(SC, Empty) { CastExprBits.PartOfExplicitCast = false; - CastExprBits.BasePathIsEmpty = BasePathSize == 0; - if (!path_empty()) - setBasePathSize(BasePathSize); + CastExprBits.BasePathSize = BasePathSize; + assert((CastExprBits.BasePathSize == BasePathSize) && + "BasePathSize overflow!"); } public: @@ -2868,13 +3064,9 @@ public: NamedDecl *getConversionFunction() const; typedef CXXBaseSpecifier **path_iterator; - typedef const CXXBaseSpecifier * const *path_const_iterator; - bool path_empty() const { return CastExprBits.BasePathIsEmpty; } - unsigned path_size() const { - if (path_empty()) - return 0U; - return *(const_cast<CastExpr *>(this)->BasePathSize()); - } + typedef const CXXBaseSpecifier *const *path_const_iterator; + bool path_empty() const { return path_size() == 0; } + unsigned path_size() const { return CastExprBits.BasePathSize; } path_iterator path_begin() { return path_buffer(); } path_iterator path_end() { return path_buffer() + path_size(); } path_const_iterator path_begin() const { return path_buffer(); } @@ -2922,17 +3114,11 @@ public: /// @endcode class ImplicitCastExpr final : public CastExpr, - private llvm::TrailingObjects<ImplicitCastExpr, CastExpr::BasePathSizeTy, - CXXBaseSpecifier *> { - size_t numTrailingObjects(OverloadToken<CastExpr::BasePathSizeTy>) const { - return path_empty() ? 0 : 1; - } + private llvm::TrailingObjects<ImplicitCastExpr, CXXBaseSpecifier *> { -private: ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, unsigned BasePathLength, ExprValueKind VK) - : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength) { - } + : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength) { } /// Construct an empty implicit cast. explicit ImplicitCastExpr(EmptyShell Shell, unsigned PathSize) @@ -2958,11 +3144,11 @@ public: static ImplicitCastExpr *CreateEmpty(const ASTContext &Context, unsigned PathSize); - SourceLocation getLocStart() const LLVM_READONLY { - return getSubExpr()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getSubExpr()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return getSubExpr()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getSubExpr()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -2975,8 +3161,13 @@ public: inline Expr *Expr::IgnoreImpCasts() { Expr *e = this; - while (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) - e = ice->getSubExpr(); + while (true) + if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) + e = ice->getSubExpr(); + else if (FullExpr *fe = dyn_cast<FullExpr>(e)) + e = fe->getSubExpr(); + else + break; return e; } @@ -3032,8 +3223,7 @@ public: /// (Type)expr. For example: @c (int)f. class CStyleCastExpr final : public ExplicitCastExpr, - private llvm::TrailingObjects<CStyleCastExpr, CastExpr::BasePathSizeTy, - CXXBaseSpecifier *> { + private llvm::TrailingObjects<CStyleCastExpr, CXXBaseSpecifier *> { SourceLocation LPLoc; // the location of the left paren SourceLocation RPLoc; // the location of the right paren @@ -3047,10 +3237,6 @@ class CStyleCastExpr final explicit CStyleCastExpr(EmptyShell Shell, unsigned PathSize) : ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { } - size_t numTrailingObjects(OverloadToken<CastExpr::BasePathSizeTy>) const { - return path_empty() ? 0 : 1; - } - public: static CStyleCastExpr *Create(const ASTContext &Context, QualType T, ExprValueKind VK, CastKind K, @@ -3067,9 +3253,9 @@ public: SourceLocation getRParenLoc() const { return RPLoc; } void setRParenLoc(SourceLocation L) { RPLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return LPLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return getSubExpr()->getLocEnd(); + SourceLocation getBeginLoc() const LLVM_READONLY { return LPLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return getSubExpr()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -3099,20 +3285,11 @@ public: /// "+" resolves to an overloaded operator, CXXOperatorCallExpr will /// be used to express the computation. class BinaryOperator : public Expr { -public: - typedef BinaryOperatorKind Opcode; - -private: - unsigned Opc : 6; - - // This is only meaningful for operations on floating point types and 0 - // otherwise. - unsigned FPFeatures : 2; - SourceLocation OpLoc; - enum { LHS, RHS, END_EXPR }; - Stmt* SubExprs[END_EXPR]; + Stmt *SubExprs[END_EXPR]; + public: + typedef BinaryOperatorKind Opcode; BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, @@ -3123,8 +3300,10 @@ public: (lhs->isInstantiationDependent() || rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || - rhs->containsUnexpandedParameterPack())), - Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) { + rhs->containsUnexpandedParameterPack())) { + BinaryOperatorBits.Opc = opc; + BinaryOperatorBits.FPFeatures = FPFeatures.getInt(); + BinaryOperatorBits.OpLoc = opLoc; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; assert(!isCompoundAssignmentOp() && @@ -3132,26 +3311,29 @@ public: } /// Construct an empty binary operator. - explicit BinaryOperator(EmptyShell Empty) - : Expr(BinaryOperatorClass, Empty), Opc(BO_Comma) { } + explicit BinaryOperator(EmptyShell Empty) : Expr(BinaryOperatorClass, Empty) { + BinaryOperatorBits.Opc = BO_Comma; + } - SourceLocation getExprLoc() const LLVM_READONLY { return OpLoc; } - SourceLocation getOperatorLoc() const { return OpLoc; } - void setOperatorLoc(SourceLocation L) { OpLoc = L; } + SourceLocation getExprLoc() const { return getOperatorLoc(); } + SourceLocation getOperatorLoc() const { return BinaryOperatorBits.OpLoc; } + void setOperatorLoc(SourceLocation L) { BinaryOperatorBits.OpLoc = L; } - Opcode getOpcode() const { return static_cast<Opcode>(Opc); } - void setOpcode(Opcode O) { Opc = O; } + Opcode getOpcode() const { + return static_cast<Opcode>(BinaryOperatorBits.Opc); + } + void setOpcode(Opcode Opc) { BinaryOperatorBits.Opc = Opc; } Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } void setLHS(Expr *E) { SubExprs[LHS] = E; } Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } - SourceLocation getLocStart() const LLVM_READONLY { - return getLHS()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getLHS()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return getRHS()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getRHS()->getEndLoc(); } /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it @@ -3169,7 +3351,11 @@ public: static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); /// predicates to categorize the respective opcodes. - bool isPtrMemOp() const { return Opc == BO_PtrMemD || Opc == BO_PtrMemI; } + static bool isPtrMemOp(Opcode Opc) { + return Opc == BO_PtrMemD || Opc == BO_PtrMemI; + } + bool isPtrMemOp() const { return isPtrMemOp(getOpcode()); } + static bool isMultiplicativeOp(Opcode Opc) { return Opc >= BO_Mul && Opc <= BO_Rem; } @@ -3268,16 +3454,24 @@ public: // Set the FP contractability status of this operator. Only meaningful for // operations on floating point types. - void setFPFeatures(FPOptions F) { FPFeatures = F.getInt(); } + void setFPFeatures(FPOptions F) { + BinaryOperatorBits.FPFeatures = F.getInt(); + } - FPOptions getFPFeatures() const { return FPOptions(FPFeatures); } + FPOptions getFPFeatures() const { + return FPOptions(BinaryOperatorBits.FPFeatures); + } // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. bool isFPContractableWithinStatement() const { - return FPOptions(FPFeatures).allowFPContractWithinStatement(); + return getFPFeatures().allowFPContractWithinStatement(); } + // Get the FENV_ACCESS status of this operator. Only meaningful for + // operations on floating point types. + bool isFEnvAccessOn() const { return getFPFeatures().allowFEnvAccess(); } + protected: BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, @@ -3288,14 +3482,17 @@ protected: (lhs->isInstantiationDependent() || rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || - rhs->containsUnexpandedParameterPack())), - Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) { + rhs->containsUnexpandedParameterPack())) { + BinaryOperatorBits.Opc = opc; + BinaryOperatorBits.FPFeatures = FPFeatures.getInt(); + BinaryOperatorBits.OpLoc = opLoc; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; } - BinaryOperator(StmtClass SC, EmptyShell Empty) - : Expr(SC, Empty), Opc(BO_MulAssign) { } + BinaryOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { + BinaryOperatorBits.Opc = BO_MulAssign; + } }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep @@ -3430,11 +3627,11 @@ public: Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } - SourceLocation getLocStart() const LLVM_READONLY { - return getCond()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getCond()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return getRHS()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getRHS()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -3518,11 +3715,11 @@ public: return cast<Expr>(SubExprs[RHS]); } - SourceLocation getLocStart() const LLVM_READONLY { - return getCommon()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getCommon()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return getFalseExpr()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getFalseExpr()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -3576,8 +3773,8 @@ public: SourceLocation getLabelLoc() const { return LabelLoc; } void setLabelLoc(SourceLocation L) { LabelLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return AmpAmpLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return LabelLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return AmpAmpLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return LabelLoc; } LabelDecl *getLabel() const { return Label; } void setLabel(LabelDecl *L) { Label = L; } @@ -3621,8 +3818,8 @@ public: const CompoundStmt *getSubStmt() const { return cast<CompoundStmt>(SubStmt); } void setSubStmt(CompoundStmt *S) { SubStmt = S; } - SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } SourceLocation getLParenLoc() const { return LParenLoc; } void setLParenLoc(SourceLocation L) { LParenLoc = L; } @@ -3670,8 +3867,8 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ShuffleVectorExprClass; @@ -3754,8 +3951,8 @@ public: /// getRParenLoc - Return the location of final right parenthesis. SourceLocation getRParenLoc() const { return RParenLoc; } - SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ConvertVectorExprClass; @@ -3835,8 +4032,8 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ChooseExprClass; @@ -3874,8 +4071,8 @@ public: SourceLocation getTokenLocation() const { return TokenLoc; } void setTokenLocation(SourceLocation L) { TokenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return TokenLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return TokenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return TokenLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return TokenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == GNUNullExprClass; @@ -3926,8 +4123,8 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == VAArgExprClass; @@ -4160,8 +4357,8 @@ public: InitListExprBits.HadArrayRangeDesignator = ARD; } - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == InitListExprClass; @@ -4395,17 +4592,17 @@ public: return ArrayOrRange.Index; } - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getBeginLoc() const LLVM_READONLY { if (Kind == FieldDesignator) return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc(); else return getLBracketLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc(); } SourceRange getSourceRange() const LLVM_READONLY { - return SourceRange(getLocStart(), getLocEnd()); + return SourceRange(getBeginLoc(), getEndLoc()); } }; @@ -4484,8 +4681,8 @@ public: SourceRange getDesignatorsSourceRange() const; - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == DesignatedInitExprClass; @@ -4526,8 +4723,8 @@ public: return T->getStmtClass() == NoInitExprClass; } - SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } // Iterators child_range children() { @@ -4561,8 +4758,8 @@ public: explicit DesignatedInitUpdateExpr(EmptyShell Empty) : Expr(DesignatedInitUpdateExprClass, Empty) { } - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == DesignatedInitUpdateExprClass; @@ -4636,11 +4833,11 @@ public: return S->getStmtClass() == ArrayInitLoopExprClass; } - SourceLocation getLocStart() const LLVM_READONLY { - return getCommonExpr()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getCommonExpr()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return getCommonExpr()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getCommonExpr()->getEndLoc(); } child_range children() { @@ -4671,8 +4868,8 @@ public: return S->getStmtClass() == ArrayInitIndexExprClass; } - SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } child_range children() { return child_range(child_iterator(), child_iterator()); @@ -4707,8 +4904,8 @@ public: return T->getStmtClass() == ImplicitValueInitExprClass; } - SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } // Iterators child_range children() { @@ -4719,31 +4916,46 @@ public: } }; -class ParenListExpr : public Expr { - Stmt **Exprs; - unsigned NumExprs; +class ParenListExpr final + : public Expr, + private llvm::TrailingObjects<ParenListExpr, Stmt *> { + friend class ASTStmtReader; + friend TrailingObjects; + + /// The location of the left and right parentheses. SourceLocation LParenLoc, RParenLoc; -public: - ParenListExpr(const ASTContext& C, SourceLocation lparenloc, - ArrayRef<Expr*> exprs, SourceLocation rparenloc); + /// Build a paren list. + ParenListExpr(SourceLocation LParenLoc, ArrayRef<Expr *> Exprs, + SourceLocation RParenLoc); /// Build an empty paren list. - explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { } + ParenListExpr(EmptyShell Empty, unsigned NumExprs); + +public: + /// Create a paren list. + static ParenListExpr *Create(const ASTContext &Ctx, SourceLocation LParenLoc, + ArrayRef<Expr *> Exprs, + SourceLocation RParenLoc); - unsigned getNumExprs() const { return NumExprs; } + /// Create an empty paren list. + static ParenListExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumExprs); - const Expr* getExpr(unsigned Init) const { + /// Return the number of expressions in this paren list. + unsigned getNumExprs() const { return ParenListExprBits.NumExprs; } + + Expr *getExpr(unsigned Init) { assert(Init < getNumExprs() && "Initializer access out of range!"); - return cast_or_null<Expr>(Exprs[Init]); + return getExprs()[Init]; } - Expr* getExpr(unsigned Init) { - assert(Init < getNumExprs() && "Initializer access out of range!"); - return cast_or_null<Expr>(Exprs[Init]); + const Expr *getExpr(unsigned Init) const { + return const_cast<ParenListExpr *>(this)->getExpr(Init); } - Expr **getExprs() { return reinterpret_cast<Expr **>(Exprs); } + Expr **getExprs() { + return reinterpret_cast<Expr **>(getTrailingObjects<Stmt *>()); + } ArrayRef<Expr *> exprs() { return llvm::makeArrayRef(getExprs(), getNumExprs()); @@ -4751,9 +4963,8 @@ public: SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } - - SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const { return getLParenLoc(); } + SourceLocation getEndLoc() const { return getRParenLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ParenListExprClass; @@ -4761,14 +4972,13 @@ public: // Iterators child_range children() { - return child_range(&Exprs[0], &Exprs[0]+NumExprs); + return child_range(getTrailingObjects<Stmt *>(), + getTrailingObjects<Stmt *>() + getNumExprs()); } const_child_range children() const { - return const_child_range(&Exprs[0], &Exprs[0] + NumExprs); + return const_child_range(getTrailingObjects<Stmt *>(), + getTrailingObjects<Stmt *>() + getNumExprs()); } - - friend class ASTStmtReader; - friend class ASTStmtWriter; }; /// Represents a C11 generic selection. @@ -4876,8 +5086,8 @@ public: const Expr *getResultExpr() const { return getAssocExpr(getResultIndex()); } Expr *getResultExpr() { return getAssocExpr(getResultIndex()); } - SourceLocation getLocStart() const LLVM_READONLY { return GenericLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return GenericLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == GenericSelectionExprClass; @@ -4942,10 +5152,10 @@ public: /// aggregate Constant of ConstantInt(s). void getEncodedElementAccess(SmallVectorImpl<uint32_t> &Elts) const; - SourceLocation getLocStart() const LLVM_READONLY { - return getBase()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getBase()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return AccessorLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return AccessorLoc; } /// isArrow - Return true if the base expression is a pointer to vector, /// return false if the base expression is a vector. @@ -4987,8 +5197,12 @@ public: const Stmt *getBody() const; Stmt *getBody(); - SourceLocation getLocStart() const LLVM_READONLY { return getCaretLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY { return getBody()->getLocEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { + return getCaretLocation(); + } + SourceLocation getEndLoc() const LLVM_READONLY { + return getBody()->getEndLoc(); + } /// getFunctionType - Return the underlying function type for this block. const FunctionProtoType *getFunctionType() const; @@ -5040,8 +5254,8 @@ public: /// getRParenLoc - Return the location of final right parenthesis. SourceLocation getRParenLoc() const { return RParenLoc; } - SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == AsTypeExprClass; @@ -5182,11 +5396,11 @@ public: return getSyntacticForm()->getExprLoc(); } - SourceLocation getLocStart() const LLVM_READONLY { - return getSyntacticForm()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getSyntacticForm()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return getSyntacticForm()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getSyntacticForm()->getEndLoc(); } child_range children() { @@ -5309,8 +5523,8 @@ public: SourceLocation getBuiltinLoc() const { return BuiltinLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } - SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == AtomicExprClass; @@ -5363,8 +5577,8 @@ public: return const_child_range(const_child_iterator(), const_child_iterator()); } - SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } static bool classof(const Stmt *T) { return T->getStmtClass() == TypoExprClass; diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 7ab8020dec64..6ef837a2fc40 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -75,43 +75,46 @@ class TemplateParameterList; /// function itself will be a (possibly empty) set of functions and /// function templates that were found by name lookup at template /// definition time. -class CXXOperatorCallExpr : public CallExpr { - /// The overloaded operator. - OverloadedOperatorKind Operator; +class CXXOperatorCallExpr final : public CallExpr { + friend class ASTStmtReader; + friend class ASTStmtWriter; SourceRange Range; - // Only meaningful for floating point types. - FPOptions FPFeatures; + // CXXOperatorCallExpr has some trailing objects belonging + // to CallExpr. See CallExpr for the details. SourceRange getSourceRangeImpl() const LLVM_READONLY; -public: - friend class ASTStmtReader; - friend class ASTStmtWriter; + CXXOperatorCallExpr(OverloadedOperatorKind OpKind, Expr *Fn, + ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK, + SourceLocation OperatorLoc, FPOptions FPFeatures, + ADLCallKind UsesADL); - CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, - ArrayRef<Expr*> args, QualType t, ExprValueKind VK, - SourceLocation operatorloc, FPOptions FPFeatures) - : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc), - Operator(Op), FPFeatures(FPFeatures) { - Range = getSourceRangeImpl(); - } + CXXOperatorCallExpr(unsigned NumArgs, EmptyShell Empty); - explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) - : CallExpr(C, CXXOperatorCallExprClass, Empty) {} +public: + static CXXOperatorCallExpr * + Create(const ASTContext &Ctx, OverloadedOperatorKind OpKind, Expr *Fn, + ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK, + SourceLocation OperatorLoc, FPOptions FPFeatures, + ADLCallKind UsesADL = NotADL); - /// Returns the kind of overloaded operator that this - /// expression refers to. - OverloadedOperatorKind getOperator() const { return Operator; } + static CXXOperatorCallExpr *CreateEmpty(const ASTContext &Ctx, + unsigned NumArgs, EmptyShell Empty); + + /// Returns the kind of overloaded operator that this expression refers to. + OverloadedOperatorKind getOperator() const { + return static_cast<OverloadedOperatorKind>( + CXXOperatorCallExprBits.OperatorKind); + } static bool isAssignmentOp(OverloadedOperatorKind Opc) { - return Opc == OO_Equal || Opc == OO_StarEqual || - Opc == OO_SlashEqual || Opc == OO_PercentEqual || - Opc == OO_PlusEqual || Opc == OO_MinusEqual || - Opc == OO_LessLessEqual || Opc == OO_GreaterGreaterEqual || - Opc == OO_AmpEqual || Opc == OO_CaretEqual || - Opc == OO_PipeEqual; + return Opc == OO_Equal || Opc == OO_StarEqual || Opc == OO_SlashEqual || + Opc == OO_PercentEqual || Opc == OO_PlusEqual || + Opc == OO_MinusEqual || Opc == OO_LessLessEqual || + Opc == OO_GreaterGreaterEqual || Opc == OO_AmpEqual || + Opc == OO_CaretEqual || Opc == OO_PipeEqual; } bool isAssignmentOp() const { return isAssignmentOp(getOperator()); } @@ -126,14 +129,15 @@ public: SourceLocation getOperatorLoc() const { return getRParenLoc(); } SourceLocation getExprLoc() const LLVM_READONLY { + OverloadedOperatorKind Operator = getOperator(); return (Operator < OO_Plus || Operator >= OO_Arrow || Operator == OO_PlusPlus || Operator == OO_MinusMinus) - ? getLocStart() + ? getBeginLoc() : getOperatorLoc(); } - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceLocation getBeginLoc() const { return Range.getBegin(); } + SourceLocation getEndLoc() const { return Range.getEnd(); } SourceRange getSourceRange() const { return Range; } static bool classof(const Stmt *T) { @@ -142,14 +146,17 @@ public: // Set the FP contractability status of this operator. Only meaningful for // operations on floating point types. - void setFPFeatures(FPOptions F) { FPFeatures = F; } - - FPOptions getFPFeatures() const { return FPFeatures; } + void setFPFeatures(FPOptions F) { + CXXOperatorCallExprBits.FPFeatures = F.getInt(); + } + FPOptions getFPFeatures() const { + return FPOptions(CXXOperatorCallExprBits.FPFeatures); + } // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. bool isFPContractableWithinStatement() const { - return FPFeatures.allowFPContractWithinStatement(); + return getFPFeatures().allowFPContractWithinStatement(); } }; @@ -161,14 +168,23 @@ public: /// both the object argument and the member function, while the /// arguments are the arguments within the parentheses (not including /// the object argument). -class CXXMemberCallExpr : public CallExpr { +class CXXMemberCallExpr final : public CallExpr { + // CXXMemberCallExpr has some trailing objects belonging + // to CallExpr. See CallExpr for the details. + + CXXMemberCallExpr(Expr *Fn, ArrayRef<Expr *> Args, QualType Ty, + ExprValueKind VK, SourceLocation RP, unsigned MinNumArgs); + + CXXMemberCallExpr(unsigned NumArgs, EmptyShell Empty); + public: - CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> args, - QualType t, ExprValueKind VK, SourceLocation RP) - : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP) {} + static CXXMemberCallExpr *Create(const ASTContext &Ctx, Expr *Fn, + ArrayRef<Expr *> Args, QualType Ty, + ExprValueKind VK, SourceLocation RP, + unsigned MinNumArgs = 0); - CXXMemberCallExpr(ASTContext &C, EmptyShell Empty) - : CallExpr(C, CXXMemberCallExprClass, Empty) {} + static CXXMemberCallExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, + EmptyShell Empty); /// Retrieves the implicit object argument for the member call. /// @@ -191,7 +207,7 @@ public: if (CLoc.isValid()) return CLoc; - return getLocStart(); + return getBeginLoc(); } static bool classof(const Stmt *T) { @@ -200,18 +216,26 @@ public: }; /// Represents a call to a CUDA kernel function. -class CUDAKernelCallExpr : public CallExpr { -private: +class CUDAKernelCallExpr final : public CallExpr { enum { CONFIG, END_PREARG }; + // CUDAKernelCallExpr has some trailing objects belonging + // to CallExpr. See CallExpr for the details. + + CUDAKernelCallExpr(Expr *Fn, CallExpr *Config, ArrayRef<Expr *> Args, + QualType Ty, ExprValueKind VK, SourceLocation RP, + unsigned MinNumArgs); + + CUDAKernelCallExpr(unsigned NumArgs, EmptyShell Empty); + public: - CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config, - ArrayRef<Expr*> args, QualType t, ExprValueKind VK, - SourceLocation RP) - : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP) {} + static CUDAKernelCallExpr *Create(const ASTContext &Ctx, Expr *Fn, + CallExpr *Config, ArrayRef<Expr *> Args, + QualType Ty, ExprValueKind VK, + SourceLocation RP, unsigned MinNumArgs = 0); - CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty) - : CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) {} + static CUDAKernelCallExpr *CreateEmpty(const ASTContext &Ctx, + unsigned NumArgs, EmptyShell Empty); const CallExpr *getConfig() const { return cast_or_null<CallExpr>(getPreArg(CONFIG)); @@ -278,8 +302,8 @@ public: /// Retrieve the location of the closing parenthesis. SourceLocation getRParenLoc() const { return RParenLoc; } - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } SourceRange getAngleBrackets() const LLVM_READONLY { return AngleBrackets; } static bool classof(const Stmt *T) { @@ -301,8 +325,7 @@ public: /// \c static_cast<int>(1.0). class CXXStaticCastExpr final : public CXXNamedCastExpr, - private llvm::TrailingObjects<CXXStaticCastExpr, CastExpr::BasePathSizeTy, - CXXBaseSpecifier *> { + private llvm::TrailingObjects<CXXStaticCastExpr, CXXBaseSpecifier *> { CXXStaticCastExpr(QualType ty, ExprValueKind vk, CastKind kind, Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation RParenLoc, @@ -313,10 +336,6 @@ class CXXStaticCastExpr final explicit CXXStaticCastExpr(EmptyShell Empty, unsigned PathSize) : CXXNamedCastExpr(CXXStaticCastExprClass, Empty, PathSize) {} - size_t numTrailingObjects(OverloadToken<CastExpr::BasePathSizeTy>) const { - return path_empty() ? 0 : 1; - } - public: friend class CastExpr; friend TrailingObjects; @@ -342,8 +361,7 @@ public: /// check to determine how to perform the type conversion. class CXXDynamicCastExpr final : public CXXNamedCastExpr, - private llvm::TrailingObjects< - CXXDynamicCastExpr, CastExpr::BasePathSizeTy, CXXBaseSpecifier *> { + private llvm::TrailingObjects<CXXDynamicCastExpr, CXXBaseSpecifier *> { CXXDynamicCastExpr(QualType ty, ExprValueKind VK, CastKind kind, Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation RParenLoc, @@ -354,10 +372,6 @@ class CXXDynamicCastExpr final explicit CXXDynamicCastExpr(EmptyShell Empty, unsigned pathSize) : CXXNamedCastExpr(CXXDynamicCastExprClass, Empty, pathSize) {} - size_t numTrailingObjects(OverloadToken<CastExpr::BasePathSizeTy>) const { - return path_empty() ? 0 : 1; - } - public: friend class CastExpr; friend TrailingObjects; @@ -390,7 +404,6 @@ public: class CXXReinterpretCastExpr final : public CXXNamedCastExpr, private llvm::TrailingObjects<CXXReinterpretCastExpr, - CastExpr::BasePathSizeTy, CXXBaseSpecifier *> { CXXReinterpretCastExpr(QualType ty, ExprValueKind vk, CastKind kind, Expr *op, unsigned pathSize, @@ -403,10 +416,6 @@ class CXXReinterpretCastExpr final CXXReinterpretCastExpr(EmptyShell Empty, unsigned pathSize) : CXXNamedCastExpr(CXXReinterpretCastExprClass, Empty, pathSize) {} - size_t numTrailingObjects(OverloadToken<CastExpr::BasePathSizeTy>) const { - return path_empty() ? 0 : 1; - } - public: friend class CastExpr; friend TrailingObjects; @@ -434,8 +443,7 @@ public: /// value. class CXXConstCastExpr final : public CXXNamedCastExpr, - private llvm::TrailingObjects<CXXConstCastExpr, CastExpr::BasePathSizeTy, - CXXBaseSpecifier *> { + private llvm::TrailingObjects<CXXConstCastExpr, CXXBaseSpecifier *> { CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation RParenLoc, SourceRange AngleBrackets) @@ -445,10 +453,6 @@ class CXXConstCastExpr final explicit CXXConstCastExpr(EmptyShell Empty) : CXXNamedCastExpr(CXXConstCastExprClass, Empty, 0) {} - size_t numTrailingObjects(OverloadToken<CastExpr::BasePathSizeTy>) const { - return path_empty() ? 0 : 1; - } - public: friend class CastExpr; friend TrailingObjects; @@ -474,22 +478,30 @@ public: /// /// Since literal operators are never found by ADL and can only be declared at /// namespace scope, a user-defined literal is never dependent. -class UserDefinedLiteral : public CallExpr { +class UserDefinedLiteral final : public CallExpr { + friend class ASTStmtReader; + friend class ASTStmtWriter; + /// The location of a ud-suffix within the literal. SourceLocation UDSuffixLoc; -public: - friend class ASTStmtReader; - friend class ASTStmtWriter; + // UserDefinedLiteral has some trailing objects belonging + // to CallExpr. See CallExpr for the details. - UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args, - QualType T, ExprValueKind VK, SourceLocation LitEndLoc, - SourceLocation SuffixLoc) - : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc), - UDSuffixLoc(SuffixLoc) {} + UserDefinedLiteral(Expr *Fn, ArrayRef<Expr *> Args, QualType Ty, + ExprValueKind VK, SourceLocation LitEndLoc, + SourceLocation SuffixLoc); - explicit UserDefinedLiteral(const ASTContext &C, EmptyShell Empty) - : CallExpr(C, UserDefinedLiteralClass, Empty) {} + UserDefinedLiteral(unsigned NumArgs, EmptyShell Empty); + +public: + static UserDefinedLiteral *Create(const ASTContext &Ctx, Expr *Fn, + ArrayRef<Expr *> Args, QualType Ty, + ExprValueKind VK, SourceLocation LitEndLoc, + SourceLocation SuffixLoc); + + static UserDefinedLiteral *CreateEmpty(const ASTContext &Ctx, + unsigned NumArgs, EmptyShell Empty); /// The kind of literal operator which is invoked. enum LiteralOperatorKind { @@ -524,13 +536,13 @@ public: return const_cast<UserDefinedLiteral*>(this)->getCookedLiteral(); } - SourceLocation getLocStart() const { + SourceLocation getBeginLoc() const { if (getLiteralOperatorKind() == LOK_Template) return getRParenLoc(); - return getArg(0)->getLocStart(); + return getArg(0)->getBeginLoc(); } - SourceLocation getLocEnd() const { return getRParenLoc(); } + SourceLocation getEndLoc() const { return getRParenLoc(); } /// Returns the location of a ud-suffix in the expression. /// @@ -548,26 +560,25 @@ public: /// A boolean literal, per ([C++ lex.bool] Boolean literals). class CXXBoolLiteralExpr : public Expr { - bool Value; - SourceLocation Loc; - public: - CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) + CXXBoolLiteralExpr(bool Val, QualType Ty, SourceLocation Loc) : Expr(CXXBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, - false, false), - Value(val), Loc(l) {} + false, false) { + CXXBoolLiteralExprBits.Value = Val; + CXXBoolLiteralExprBits.Loc = Loc; + } explicit CXXBoolLiteralExpr(EmptyShell Empty) : Expr(CXXBoolLiteralExprClass, Empty) {} - bool getValue() const { return Value; } - void setValue(bool V) { Value = V; } + bool getValue() const { return CXXBoolLiteralExprBits.Value; } + void setValue(bool V) { CXXBoolLiteralExprBits.Value = V; } - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const { return getLocation(); } + SourceLocation getEndLoc() const { return getLocation(); } - SourceLocation getLocation() const { return Loc; } - void setLocation(SourceLocation L) { Loc = L; } + SourceLocation getLocation() const { return CXXBoolLiteralExprBits.Loc; } + void setLocation(SourceLocation L) { CXXBoolLiteralExprBits.Loc = L; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXBoolLiteralExprClass; @@ -583,22 +594,21 @@ public: /// /// Introduced in C++11, the only literal of type \c nullptr_t is \c nullptr. class CXXNullPtrLiteralExpr : public Expr { - SourceLocation Loc; - public: - CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) + CXXNullPtrLiteralExpr(QualType Ty, SourceLocation Loc) : Expr(CXXNullPtrLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, - false, false, false), - Loc(l) {} + false, false, false) { + CXXNullPtrLiteralExprBits.Loc = Loc; + } explicit CXXNullPtrLiteralExpr(EmptyShell Empty) : Expr(CXXNullPtrLiteralExprClass, Empty) {} - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const { return getLocation(); } + SourceLocation getEndLoc() const { return getLocation(); } - SourceLocation getLocation() const { return Loc; } - void setLocation(SourceLocation L) { Loc = L; } + SourceLocation getLocation() const { return CXXNullPtrLiteralExprBits.Loc; } + void setLocation(SourceLocation L) { CXXNullPtrLiteralExprBits.Loc = L; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXNullPtrLiteralExprClass; @@ -631,12 +641,12 @@ public: Expr *getSubExpr() { return static_cast<Expr*>(SubExpr); } const Expr *getSubExpr() const { return static_cast<const Expr*>(SubExpr); } - SourceLocation getLocStart() const LLVM_READONLY { - return SubExpr->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return SubExpr->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return SubExpr->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return SubExpr->getEndLoc(); } /// Retrieve the source range of the expression. @@ -723,8 +733,8 @@ public: Operand = E; } - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } SourceRange getSourceRange() const LLVM_READONLY { return Range; } void setSourceRange(SourceRange R) { Range = R; } @@ -771,23 +781,23 @@ public: MSPropertyRefExpr(EmptyShell Empty) : Expr(MSPropertyRefExprClass, Empty) {} SourceRange getSourceRange() const LLVM_READONLY { - return SourceRange(getLocStart(), getLocEnd()); + return SourceRange(getBeginLoc(), getEndLoc()); } bool isImplicitAccess() const { return getBaseExpr() && getBaseExpr()->isImplicitCXXThis(); } - SourceLocation getLocStart() const { + SourceLocation getBeginLoc() const { if (!isImplicitAccess()) - return BaseExpr->getLocStart(); + return BaseExpr->getBeginLoc(); else if (QualifierLoc) return QualifierLoc.getBeginLoc(); else return MemberLoc; } - SourceLocation getLocEnd() const { return getMemberLoc(); } + SourceLocation getEndLoc() const { return getMemberLoc(); } child_range children() { return child_range((Stmt**)&BaseExpr, (Stmt**)&BaseExpr + 1); @@ -847,11 +857,11 @@ public: Expr *getIdx() { return cast<Expr>(SubExprs[IDX_EXPR]); } const Expr *getIdx() const { return cast<Expr>(SubExprs[IDX_EXPR]); } - SourceLocation getLocStart() const LLVM_READONLY { - return getBase()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getBase()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; } SourceLocation getRBracketLoc() const { return RBracketLoc; } void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } @@ -933,8 +943,8 @@ public: void setUuidStr(StringRef US) { UuidStr = US; } StringRef getUuidStr() const { return UuidStr; } - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } SourceRange getSourceRange() const LLVM_READONLY { return Range; } void setSourceRange(SourceRange R) { Range = R; } @@ -964,29 +974,28 @@ public: /// }; /// \endcode class CXXThisExpr : public Expr { - SourceLocation Loc; - bool Implicit : 1; - public: - CXXThisExpr(SourceLocation L, QualType Type, bool isImplicit) - : Expr(CXXThisExprClass, Type, VK_RValue, OK_Ordinary, + CXXThisExpr(SourceLocation L, QualType Ty, bool IsImplicit) + : Expr(CXXThisExprClass, Ty, VK_RValue, OK_Ordinary, // 'this' is type-dependent if the class type of the enclosing // member function is dependent (C++ [temp.dep.expr]p2) - Type->isDependentType(), Type->isDependentType(), - Type->isInstantiationDependentType(), - /*ContainsUnexpandedParameterPack=*/false), - Loc(L), Implicit(isImplicit) {} + Ty->isDependentType(), Ty->isDependentType(), + Ty->isInstantiationDependentType(), + /*ContainsUnexpandedParameterPack=*/false) { + CXXThisExprBits.IsImplicit = IsImplicit; + CXXThisExprBits.Loc = L; + } CXXThisExpr(EmptyShell Empty) : Expr(CXXThisExprClass, Empty) {} - SourceLocation getLocation() const { return Loc; } - void setLocation(SourceLocation L) { Loc = L; } + SourceLocation getLocation() const { return CXXThisExprBits.Loc; } + void setLocation(SourceLocation L) { CXXThisExprBits.Loc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const { return getLocation(); } + SourceLocation getEndLoc() const { return getLocation(); } - bool isImplicit() const { return Implicit; } - void setImplicit(bool I) { Implicit = I; } + bool isImplicit() const { return CXXThisExprBits.IsImplicit; } + void setImplicit(bool I) { CXXThisExprBits.IsImplicit = I; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXThisExprClass; @@ -1006,43 +1015,44 @@ public: class CXXThrowExpr : public Expr { friend class ASTStmtReader; - Stmt *Op; - SourceLocation ThrowLoc; - - /// Whether the thrown variable (if any) is in scope. - unsigned IsThrownVariableInScope : 1; + /// The optional expression in the throw statement. + Stmt *Operand; public: // \p Ty is the void type which is used as the result type of the - // expression. The \p l is the location of the throw keyword. \p expr - // can by null, if the optional expression to throw isn't present. - CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l, + // expression. The \p Loc is the location of the throw keyword. + // \p Operand is the expression in the throw statement, and can be + // null if not present. + CXXThrowExpr(Expr *Operand, QualType Ty, SourceLocation Loc, bool IsThrownVariableInScope) : Expr(CXXThrowExprClass, Ty, VK_RValue, OK_Ordinary, false, false, - expr && expr->isInstantiationDependent(), - expr && expr->containsUnexpandedParameterPack()), - Op(expr), ThrowLoc(l), - IsThrownVariableInScope(IsThrownVariableInScope) {} + Operand && Operand->isInstantiationDependent(), + Operand && Operand->containsUnexpandedParameterPack()), + Operand(Operand) { + CXXThrowExprBits.ThrowLoc = Loc; + CXXThrowExprBits.IsThrownVariableInScope = IsThrownVariableInScope; + } CXXThrowExpr(EmptyShell Empty) : Expr(CXXThrowExprClass, Empty) {} - const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); } - Expr *getSubExpr() { return cast_or_null<Expr>(Op); } + const Expr *getSubExpr() const { return cast_or_null<Expr>(Operand); } + Expr *getSubExpr() { return cast_or_null<Expr>(Operand); } - SourceLocation getThrowLoc() const { return ThrowLoc; } + SourceLocation getThrowLoc() const { return CXXThrowExprBits.ThrowLoc; } /// Determines whether the variable thrown by this expression (if any!) /// is within the innermost try block. /// /// This information is required to determine whether the NRVO can apply to /// this variable. - bool isThrownVariableInScope() const { return IsThrownVariableInScope; } - - SourceLocation getLocStart() const LLVM_READONLY { return ThrowLoc; } + bool isThrownVariableInScope() const { + return CXXThrowExprBits.IsThrownVariableInScope; + } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getBeginLoc() const { return getThrowLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { if (!getSubExpr()) - return ThrowLoc; - return getSubExpr()->getLocEnd(); + return getThrowLoc(); + return getSubExpr()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -1051,7 +1061,7 @@ public: // Iterators child_range children() { - return child_range(&Op, Op ? &Op+1 : &Op); + return child_range(&Operand, Operand ? &Operand + 1 : &Operand); } }; @@ -1061,26 +1071,24 @@ public: /// corresponding parameter's default argument, when the call did not /// explicitly supply arguments for all of the parameters. class CXXDefaultArgExpr final : public Expr { + friend class ASTStmtReader; + /// The parameter whose default is being used. ParmVarDecl *Param; - /// The location where the default argument expression was used. - SourceLocation Loc; - - CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param) + CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *Param) : Expr(SC, - param->hasUnparsedDefaultArg() - ? param->getType().getNonReferenceType() - : param->getDefaultArg()->getType(), - param->getDefaultArg()->getValueKind(), - param->getDefaultArg()->getObjectKind(), false, false, false, + Param->hasUnparsedDefaultArg() + ? Param->getType().getNonReferenceType() + : Param->getDefaultArg()->getType(), + Param->getDefaultArg()->getValueKind(), + Param->getDefaultArg()->getObjectKind(), false, false, false, false), - Param(param), Loc(Loc) {} + Param(Param) { + CXXDefaultArgExprBits.Loc = Loc; + } public: - friend class ASTStmtReader; - friend class ASTStmtWriter; - CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {} // \p Param is the parameter whose default argument is used by this @@ -1095,23 +1103,18 @@ public: ParmVarDecl *getParam() { return Param; } // Retrieve the actual argument to the function call. - const Expr *getExpr() const { - return getParam()->getDefaultArg(); - } - Expr *getExpr() { - return getParam()->getDefaultArg(); - } + const Expr *getExpr() const { return getParam()->getDefaultArg(); } + Expr *getExpr() { return getParam()->getDefaultArg(); } - /// Retrieve the location where this default argument was actually - /// used. - SourceLocation getUsedLocation() const { return Loc; } + /// Retrieve the location where this default argument was actually used. + SourceLocation getUsedLocation() const { return CXXDefaultArgExprBits.Loc; } /// Default argument expressions have no representation in the /// source, so they have an empty source range. - SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getBeginLoc() const { return SourceLocation(); } + SourceLocation getEndLoc() const { return SourceLocation(); } - SourceLocation getExprLoc() const LLVM_READONLY { return Loc; } + SourceLocation getExprLoc() const { return getUsedLocation(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXDefaultArgExprClass; @@ -1132,26 +1135,23 @@ public: /// (C++11 [class.base.init]p8) or in aggregate initialization /// (C++1y [dcl.init.aggr]p7). class CXXDefaultInitExpr : public Expr { + friend class ASTReader; + friend class ASTStmtReader; + /// The field whose default is being used. FieldDecl *Field; - /// The location where the default initializer expression was used. - SourceLocation Loc; - - CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc, FieldDecl *Field, - QualType T); + CXXDefaultInitExpr(const ASTContext &Ctx, SourceLocation Loc, + FieldDecl *Field, QualType Ty); CXXDefaultInitExpr(EmptyShell Empty) : Expr(CXXDefaultInitExprClass, Empty) {} public: - friend class ASTReader; - friend class ASTStmtReader; - /// \p Field is the non-static data member whose default initializer is used /// by this expression. - static CXXDefaultInitExpr *Create(const ASTContext &C, SourceLocation Loc, + static CXXDefaultInitExpr *Create(const ASTContext &Ctx, SourceLocation Loc, FieldDecl *Field) { - return new (C) CXXDefaultInitExpr(C, Loc, Field, Field->getType()); + return new (Ctx) CXXDefaultInitExpr(Ctx, Loc, Field, Field->getType()); } /// Get the field whose initializer will be used. @@ -1168,8 +1168,8 @@ public: return Field->getInClassInitializer(); } - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const { return CXXDefaultInitExprBits.Loc; } + SourceLocation getEndLoc() const { return CXXDefaultInitExprBits.Loc; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXDefaultInitExprClass; @@ -1241,11 +1241,13 @@ public: Expr *getSubExpr() { return cast<Expr>(SubExpr); } void setSubExpr(Expr *E) { SubExpr = E; } - SourceLocation getLocStart() const LLVM_READONLY { - return SubExpr->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return SubExpr->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd();} + SourceLocation getEndLoc() const LLVM_READONLY { + return SubExpr->getEndLoc(); + } // Implement isa/cast/dyncast/etc. static bool classof(const Stmt *T) { @@ -1258,6 +1260,8 @@ public: /// Represents a call to a C++ constructor. class CXXConstructExpr : public Expr { + friend class ASTStmtReader; + public: enum ConstructionKind { CK_Complete, @@ -1267,150 +1271,173 @@ public: }; private: - CXXConstructorDecl *Constructor = nullptr; - SourceLocation Loc; + /// A pointer to the constructor which will be ultimately called. + CXXConstructorDecl *Constructor; + SourceRange ParenOrBraceRange; - unsigned NumArgs : 16; - unsigned Elidable : 1; - unsigned HadMultipleCandidates : 1; - unsigned ListInitialization : 1; - unsigned StdInitListInitialization : 1; - unsigned ZeroInitialization : 1; - unsigned ConstructKind : 2; - Stmt **Args = nullptr; - void setConstructor(CXXConstructorDecl *C) { Constructor = C; } + /// The number of arguments. + unsigned NumArgs; + + // We would like to stash the arguments of the constructor call after + // CXXConstructExpr. However CXXConstructExpr is used as a base class of + // CXXTemporaryObjectExpr which makes the use of llvm::TrailingObjects + // impossible. + // + // Instead we manually stash the trailing object after the full object + // containing CXXConstructExpr (that is either CXXConstructExpr or + // CXXTemporaryObjectExpr). + // + // The trailing objects are: + // + // * An array of getNumArgs() "Stmt *" for the arguments of the + // constructor call. + + /// Return a pointer to the start of the trailing arguments. + /// Defined just after CXXTemporaryObjectExpr. + inline Stmt **getTrailingArgs(); + const Stmt *const *getTrailingArgs() const { + return const_cast<CXXConstructExpr *>(this)->getTrailingArgs(); + } protected: - CXXConstructExpr(const ASTContext &C, StmtClass SC, QualType T, - SourceLocation Loc, - CXXConstructorDecl *Ctor, - bool Elidable, - ArrayRef<Expr *> Args, - bool HadMultipleCandidates, - bool ListInitialization, - bool StdInitListInitialization, - bool ZeroInitialization, - ConstructionKind ConstructKind, + /// Build a C++ construction expression. + CXXConstructExpr(StmtClass SC, QualType Ty, SourceLocation Loc, + CXXConstructorDecl *Ctor, bool Elidable, + ArrayRef<Expr *> Args, bool HadMultipleCandidates, + bool ListInitialization, bool StdInitListInitialization, + bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenOrBraceRange); - /// Construct an empty C++ construction expression. - CXXConstructExpr(StmtClass SC, EmptyShell Empty) - : Expr(SC, Empty), NumArgs(0), Elidable(false), - HadMultipleCandidates(false), ListInitialization(false), - ZeroInitialization(false), ConstructKind(0) {} + /// Build an empty C++ construction expression. + CXXConstructExpr(StmtClass SC, EmptyShell Empty, unsigned NumArgs); -public: - friend class ASTStmtReader; + /// Return the size in bytes of the trailing objects. Used by + /// CXXTemporaryObjectExpr to allocate the right amount of storage. + static unsigned sizeOfTrailingObjects(unsigned NumArgs) { + return NumArgs * sizeof(Stmt *); + } - /// Construct an empty C++ construction expression. - explicit CXXConstructExpr(EmptyShell Empty) - : CXXConstructExpr(CXXConstructExprClass, Empty) {} +public: + /// Create a C++ construction expression. + static CXXConstructExpr * + Create(const ASTContext &Ctx, QualType Ty, SourceLocation Loc, + CXXConstructorDecl *Ctor, bool Elidable, ArrayRef<Expr *> Args, + bool HadMultipleCandidates, bool ListInitialization, + bool StdInitListInitialization, bool ZeroInitialization, + ConstructionKind ConstructKind, SourceRange ParenOrBraceRange); - static CXXConstructExpr *Create(const ASTContext &C, QualType T, - SourceLocation Loc, - CXXConstructorDecl *Ctor, - bool Elidable, - ArrayRef<Expr *> Args, - bool HadMultipleCandidates, - bool ListInitialization, - bool StdInitListInitialization, - bool ZeroInitialization, - ConstructionKind ConstructKind, - SourceRange ParenOrBraceRange); + /// Create an empty C++ construction expression. + static CXXConstructExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumArgs); /// Get the constructor that this expression will (ultimately) call. CXXConstructorDecl *getConstructor() const { return Constructor; } - SourceLocation getLocation() const { return Loc; } - void setLocation(SourceLocation Loc) { this->Loc = Loc; } + SourceLocation getLocation() const { return CXXConstructExprBits.Loc; } + void setLocation(SourceLocation Loc) { CXXConstructExprBits.Loc = Loc; } /// Whether this construction is elidable. - bool isElidable() const { return Elidable; } - void setElidable(bool E) { Elidable = E; } + bool isElidable() const { return CXXConstructExprBits.Elidable; } + void setElidable(bool E) { CXXConstructExprBits.Elidable = E; } /// Whether the referred constructor was resolved from /// an overloaded set having size greater than 1. - bool hadMultipleCandidates() const { return HadMultipleCandidates; } - void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; } + bool hadMultipleCandidates() const { + return CXXConstructExprBits.HadMultipleCandidates; + } + void setHadMultipleCandidates(bool V) { + CXXConstructExprBits.HadMultipleCandidates = V; + } /// Whether this constructor call was written as list-initialization. - bool isListInitialization() const { return ListInitialization; } - void setListInitialization(bool V) { ListInitialization = V; } + bool isListInitialization() const { + return CXXConstructExprBits.ListInitialization; + } + void setListInitialization(bool V) { + CXXConstructExprBits.ListInitialization = V; + } /// Whether this constructor call was written as list-initialization, /// but was interpreted as forming a std::initializer_list<T> from the list /// and passing that as a single constructor argument. /// See C++11 [over.match.list]p1 bullet 1. - bool isStdInitListInitialization() const { return StdInitListInitialization; } - void setStdInitListInitialization(bool V) { StdInitListInitialization = V; } + bool isStdInitListInitialization() const { + return CXXConstructExprBits.StdInitListInitialization; + } + void setStdInitListInitialization(bool V) { + CXXConstructExprBits.StdInitListInitialization = V; + } /// Whether this construction first requires /// zero-initialization before the initializer is called. - bool requiresZeroInitialization() const { return ZeroInitialization; } + bool requiresZeroInitialization() const { + return CXXConstructExprBits.ZeroInitialization; + } void setRequiresZeroInitialization(bool ZeroInit) { - ZeroInitialization = ZeroInit; + CXXConstructExprBits.ZeroInitialization = ZeroInit; } /// Determine whether this constructor is actually constructing /// a base class (rather than a complete object). ConstructionKind getConstructionKind() const { - return (ConstructionKind)ConstructKind; + return static_cast<ConstructionKind>(CXXConstructExprBits.ConstructionKind); } void setConstructionKind(ConstructionKind CK) { - ConstructKind = CK; + CXXConstructExprBits.ConstructionKind = CK; } using arg_iterator = ExprIterator; using const_arg_iterator = ConstExprIterator; using arg_range = llvm::iterator_range<arg_iterator>; - using arg_const_range = llvm::iterator_range<const_arg_iterator>; + using const_arg_range = llvm::iterator_range<const_arg_iterator>; arg_range arguments() { return arg_range(arg_begin(), arg_end()); } - arg_const_range arguments() const { - return arg_const_range(arg_begin(), arg_end()); + const_arg_range arguments() const { + return const_arg_range(arg_begin(), arg_end()); } - arg_iterator arg_begin() { return Args; } - arg_iterator arg_end() { return Args + NumArgs; } - const_arg_iterator arg_begin() const { return Args; } - const_arg_iterator arg_end() const { return Args + NumArgs; } + arg_iterator arg_begin() { return getTrailingArgs(); } + arg_iterator arg_end() { return arg_begin() + getNumArgs(); } + const_arg_iterator arg_begin() const { return getTrailingArgs(); } + const_arg_iterator arg_end() const { return arg_begin() + getNumArgs(); } - Expr **getArgs() { return reinterpret_cast<Expr **>(Args); } + Expr **getArgs() { return reinterpret_cast<Expr **>(getTrailingArgs()); } const Expr *const *getArgs() const { - return const_cast<CXXConstructExpr *>(this)->getArgs(); + return reinterpret_cast<const Expr *const *>(getTrailingArgs()); } + + /// Return the number of arguments to the constructor call. unsigned getNumArgs() const { return NumArgs; } /// Return the specified argument. Expr *getArg(unsigned Arg) { - assert(Arg < NumArgs && "Arg access out of range!"); - return cast<Expr>(Args[Arg]); + assert(Arg < getNumArgs() && "Arg access out of range!"); + return getArgs()[Arg]; } const Expr *getArg(unsigned Arg) const { - assert(Arg < NumArgs && "Arg access out of range!"); - return cast<Expr>(Args[Arg]); + assert(Arg < getNumArgs() && "Arg access out of range!"); + return getArgs()[Arg]; } /// Set the specified argument. void setArg(unsigned Arg, Expr *ArgExpr) { - assert(Arg < NumArgs && "Arg access out of range!"); - Args[Arg] = ArgExpr; + assert(Arg < getNumArgs() && "Arg access out of range!"); + getArgs()[Arg] = ArgExpr; } - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; SourceRange getParenOrBraceRange() const { return ParenOrBraceRange; } void setParenOrBraceRange(SourceRange Range) { ParenOrBraceRange = Range; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXConstructExprClass || - T->getStmtClass() == CXXTemporaryObjectExprClass; + T->getStmtClass() == CXXTemporaryObjectExprClass; } // Iterators child_range children() { - return child_range(&Args[0], &Args[0]+NumArgs); + return child_range(getTrailingArgs(), getTrailingArgs() + getNumArgs()); } }; @@ -1470,8 +1497,8 @@ public: bool inheritedFromVBase() const { return InheritedFromVirtualBase; } SourceLocation getLocation() const LLVM_READONLY { return Loc; } - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXInheritedCtorInitExprClass; @@ -1491,8 +1518,7 @@ public: /// \endcode class CXXFunctionalCastExpr final : public ExplicitCastExpr, - private llvm::TrailingObjects< - CXXFunctionalCastExpr, CastExpr::BasePathSizeTy, CXXBaseSpecifier *> { + private llvm::TrailingObjects<CXXFunctionalCastExpr, CXXBaseSpecifier *> { SourceLocation LParenLoc; SourceLocation RParenLoc; @@ -1507,10 +1533,6 @@ class CXXFunctionalCastExpr final explicit CXXFunctionalCastExpr(EmptyShell Shell, unsigned PathSize) : ExplicitCastExpr(CXXFunctionalCastExprClass, Shell, PathSize) {} - size_t numTrailingObjects(OverloadToken<CastExpr::BasePathSizeTy>) const { - return path_empty() ? 0 : 1; - } - public: friend class CastExpr; friend TrailingObjects; @@ -1533,8 +1555,8 @@ public: /// Determine whether this expression models list-initialization. bool isListInitialization() const { return LParenLoc.isInvalid(); } - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == CXXFunctionalCastExprClass; @@ -1556,35 +1578,53 @@ public: /// return X(1, 3.14f); // creates a CXXTemporaryObjectExpr /// }; /// \endcode -class CXXTemporaryObjectExpr : public CXXConstructExpr { - TypeSourceInfo *Type = nullptr; - -public: +class CXXTemporaryObjectExpr final : public CXXConstructExpr { friend class ASTStmtReader; - CXXTemporaryObjectExpr(const ASTContext &C, - CXXConstructorDecl *Cons, - QualType Type, - TypeSourceInfo *TSI, - ArrayRef<Expr *> Args, + // CXXTemporaryObjectExpr has some trailing objects belonging + // to CXXConstructExpr. See the comment inside CXXConstructExpr + // for more details. + + TypeSourceInfo *TSI; + + CXXTemporaryObjectExpr(CXXConstructorDecl *Cons, QualType Ty, + TypeSourceInfo *TSI, ArrayRef<Expr *> Args, SourceRange ParenOrBraceRange, - bool HadMultipleCandidates, - bool ListInitialization, + bool HadMultipleCandidates, bool ListInitialization, bool StdInitListInitialization, bool ZeroInitialization); - explicit CXXTemporaryObjectExpr(EmptyShell Empty) - : CXXConstructExpr(CXXTemporaryObjectExprClass, Empty) {} - TypeSourceInfo *getTypeSourceInfo() const { return Type; } + CXXTemporaryObjectExpr(EmptyShell Empty, unsigned NumArgs); + +public: + static CXXTemporaryObjectExpr * + Create(const ASTContext &Ctx, CXXConstructorDecl *Cons, QualType Ty, + TypeSourceInfo *TSI, ArrayRef<Expr *> Args, + SourceRange ParenOrBraceRange, bool HadMultipleCandidates, + bool ListInitialization, bool StdInitListInitialization, + bool ZeroInitialization); - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + static CXXTemporaryObjectExpr *CreateEmpty(const ASTContext &Ctx, + unsigned NumArgs); + + TypeSourceInfo *getTypeSourceInfo() const { return TSI; } + + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == CXXTemporaryObjectExprClass; } }; +Stmt **CXXConstructExpr::getTrailingArgs() { + if (auto *E = dyn_cast<CXXTemporaryObjectExpr>(this)) + return reinterpret_cast<Stmt **>(E + 1); + assert((getStmtClass() == CXXConstructExprClass) && + "Unexpected class deriving from CXXConstructExpr!"); + return reinterpret_cast<Stmt **>(this + 1); +} + /// A C++ lambda expression, which produces a function object /// (of unspecified type) that can be invoked later. /// @@ -1814,11 +1854,11 @@ public: return T->getStmtClass() == LambdaExprClass; } - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getBeginLoc() const LLVM_READONLY { return IntroducerRange.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return ClosingBrace; } + SourceLocation getEndLoc() const LLVM_READONLY { return ClosingBrace; } child_range children() { // Includes initialization exprs plus body stmt @@ -1831,18 +1871,19 @@ public: class CXXScalarValueInitExpr : public Expr { friend class ASTStmtReader; - SourceLocation RParenLoc; TypeSourceInfo *TypeInfo; public: /// Create an explicitly-written scalar-value initialization /// expression. CXXScalarValueInitExpr(QualType Type, TypeSourceInfo *TypeInfo, - SourceLocation rParenLoc) - : Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary, - false, false, Type->isInstantiationDependentType(), + SourceLocation RParenLoc) + : Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary, false, + false, Type->isInstantiationDependentType(), Type->containsUnexpandedParameterPack()), - RParenLoc(rParenLoc), TypeInfo(TypeInfo) {} + TypeInfo(TypeInfo) { + CXXScalarValueInitExprBits.RParenLoc = RParenLoc; + } explicit CXXScalarValueInitExpr(EmptyShell Shell) : Expr(CXXScalarValueInitExprClass, Shell) {} @@ -1851,10 +1892,12 @@ public: return TypeInfo; } - SourceLocation getRParenLoc() const { return RParenLoc; } + SourceLocation getRParenLoc() const { + return CXXScalarValueInitExprBits.RParenLoc; + } - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const { return getRParenLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXScalarValueInitExprClass; @@ -1868,54 +1911,56 @@ public: /// Represents a new-expression for memory allocation and constructor /// calls, e.g: "new CXXNewExpr(foo)". -class CXXNewExpr : public Expr { +class CXXNewExpr final + : public Expr, + private llvm::TrailingObjects<CXXNewExpr, Stmt *, SourceRange> { friend class ASTStmtReader; friend class ASTStmtWriter; - - /// Contains an optional array size expression, an optional initialization - /// expression, and any number of optional placement arguments, in that order. - Stmt **SubExprs = nullptr; + friend TrailingObjects; /// Points to the allocation function used. FunctionDecl *OperatorNew; - /// Points to the deallocation function used in case of error. May be - /// null. + /// Points to the deallocation function used in case of error. May be null. FunctionDecl *OperatorDelete; /// The allocated type-source information, as written in the source. TypeSourceInfo *AllocatedTypeInfo; - /// If the allocated type was expressed as a parenthesized type-id, - /// the source range covering the parenthesized type-id. - SourceRange TypeIdParens; - /// Range of the entire new expression. SourceRange Range; /// Source-range of a paren-delimited initializer. SourceRange DirectInitRange; - /// Was the usage ::new, i.e. is the global new to be used? - unsigned GlobalNew : 1; - - /// Do we allocate an array? If so, the first SubExpr is the size expression. - unsigned Array : 1; - - /// Should the alignment be passed to the allocation function? - unsigned PassAlignment : 1; - - /// If this is an array allocation, does the usual deallocation - /// function for the allocated type want to know the allocated size? - unsigned UsualArrayDeleteWantsSize : 1; + // CXXNewExpr is followed by several optional trailing objects. + // They are in order: + // + // * An optional "Stmt *" for the array size expression. + // Present if and ony if isArray(). + // + // * An optional "Stmt *" for the init expression. + // Present if and only if hasInitializer(). + // + // * An array of getNumPlacementArgs() "Stmt *" for the placement new + // arguments, if any. + // + // * An optional SourceRange for the range covering the parenthesized type-id + // if the allocated type was expressed as a parenthesized type-id. + // Present if and only if isParenTypeId(). + unsigned arraySizeOffset() const { return 0; } + unsigned initExprOffset() const { return arraySizeOffset() + isArray(); } + unsigned placementNewArgsOffset() const { + return initExprOffset() + hasInitializer(); + } - /// The number of placement new arguments. - unsigned NumPlacementArgs : 26; + unsigned numTrailingObjects(OverloadToken<Stmt *>) const { + return isArray() + hasInitializer() + getNumPlacementArgs(); + } - /// What kind of initializer do we have? Could be none, parens, or braces. - /// In storage, we distinguish between "none, and no initializer expr", and - /// "none, but an implicit initializer expr". - unsigned StoredInitializationStyle : 2; + unsigned numTrailingObjects(OverloadToken<SourceRange>) const { + return isParenTypeId(); + } public: enum InitializationStyle { @@ -1929,18 +1974,35 @@ public: ListInit }; - CXXNewExpr(const ASTContext &C, bool globalNew, FunctionDecl *operatorNew, - FunctionDecl *operatorDelete, bool PassAlignment, - bool usualArrayDeleteWantsSize, ArrayRef<Expr*> placementArgs, - SourceRange typeIdParens, Expr *arraySize, - InitializationStyle initializationStyle, Expr *initializer, - QualType ty, TypeSourceInfo *AllocatedTypeInfo, - SourceRange Range, SourceRange directInitRange); - explicit CXXNewExpr(EmptyShell Shell) - : Expr(CXXNewExprClass, Shell) {} +private: + /// Build a c++ new expression. + CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew, + FunctionDecl *OperatorDelete, bool ShouldPassAlignment, + bool UsualArrayDeleteWantsSize, ArrayRef<Expr *> PlacementArgs, + SourceRange TypeIdParens, Expr *ArraySize, + InitializationStyle InitializationStyle, Expr *Initializer, + QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range, + SourceRange DirectInitRange); + + /// Build an empty c++ new expression. + CXXNewExpr(EmptyShell Empty, bool IsArray, unsigned NumPlacementArgs, + bool IsParenTypeId); + +public: + /// Create a c++ new expression. + static CXXNewExpr * + Create(const ASTContext &Ctx, bool IsGlobalNew, FunctionDecl *OperatorNew, + FunctionDecl *OperatorDelete, bool ShouldPassAlignment, + bool UsualArrayDeleteWantsSize, ArrayRef<Expr *> PlacementArgs, + SourceRange TypeIdParens, Expr *ArraySize, + InitializationStyle InitializationStyle, Expr *Initializer, + QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range, + SourceRange DirectInitRange); - void AllocateArgsArray(const ASTContext &C, bool isArray, - unsigned numPlaceArgs, bool hasInitializer); + /// Create an empty c++ new expression. + static CXXNewExpr *CreateEmpty(const ASTContext &Ctx, bool IsArray, + bool HasInit, unsigned NumPlacementArgs, + bool IsParenTypeId); QualType getAllocatedType() const { assert(getType()->isPointerType()); @@ -1966,58 +2028,74 @@ public: /// has a non-throwing exception-specification. The '03 rule is /// identical except that the definition of a non-throwing /// exception specification is just "is it throw()?". - bool shouldNullCheckAllocation(const ASTContext &Ctx) const; + bool shouldNullCheckAllocation() const; FunctionDecl *getOperatorNew() const { return OperatorNew; } void setOperatorNew(FunctionDecl *D) { OperatorNew = D; } FunctionDecl *getOperatorDelete() const { return OperatorDelete; } void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; } - bool isArray() const { return Array; } + bool isArray() const { return CXXNewExprBits.IsArray; } Expr *getArraySize() { - return Array ? cast<Expr>(SubExprs[0]) : nullptr; + return isArray() + ? cast<Expr>(getTrailingObjects<Stmt *>()[arraySizeOffset()]) + : nullptr; } const Expr *getArraySize() const { - return Array ? cast<Expr>(SubExprs[0]) : nullptr; + return isArray() + ? cast<Expr>(getTrailingObjects<Stmt *>()[arraySizeOffset()]) + : nullptr; } - unsigned getNumPlacementArgs() const { return NumPlacementArgs; } + unsigned getNumPlacementArgs() const { + return CXXNewExprBits.NumPlacementArgs; + } Expr **getPlacementArgs() { - return reinterpret_cast<Expr **>(SubExprs + Array + hasInitializer()); + return reinterpret_cast<Expr **>(getTrailingObjects<Stmt *>() + + placementNewArgsOffset()); } - Expr *getPlacementArg(unsigned i) { - assert(i < NumPlacementArgs && "Index out of range"); - return getPlacementArgs()[i]; + Expr *getPlacementArg(unsigned I) { + assert((I < getNumPlacementArgs()) && "Index out of range!"); + return getPlacementArgs()[I]; } - const Expr *getPlacementArg(unsigned i) const { - assert(i < NumPlacementArgs && "Index out of range"); - return const_cast<CXXNewExpr*>(this)->getPlacementArg(i); + const Expr *getPlacementArg(unsigned I) const { + return const_cast<CXXNewExpr *>(this)->getPlacementArg(I); } - bool isParenTypeId() const { return TypeIdParens.isValid(); } - SourceRange getTypeIdParens() const { return TypeIdParens; } + bool isParenTypeId() const { return CXXNewExprBits.IsParenTypeId; } + SourceRange getTypeIdParens() const { + return isParenTypeId() ? getTrailingObjects<SourceRange>()[0] + : SourceRange(); + } - bool isGlobalNew() const { return GlobalNew; } + bool isGlobalNew() const { return CXXNewExprBits.IsGlobalNew; } /// Whether this new-expression has any initializer at all. - bool hasInitializer() const { return StoredInitializationStyle > 0; } + bool hasInitializer() const { + return CXXNewExprBits.StoredInitializationStyle > 0; + } /// The kind of initializer this new-expression has. InitializationStyle getInitializationStyle() const { - if (StoredInitializationStyle == 0) + if (CXXNewExprBits.StoredInitializationStyle == 0) return NoInit; - return static_cast<InitializationStyle>(StoredInitializationStyle-1); + return static_cast<InitializationStyle>( + CXXNewExprBits.StoredInitializationStyle - 1); } /// The initializer of this new-expression. Expr *getInitializer() { - return hasInitializer() ? cast<Expr>(SubExprs[Array]) : nullptr; + return hasInitializer() + ? cast<Expr>(getTrailingObjects<Stmt *>()[initExprOffset()]) + : nullptr; } const Expr *getInitializer() const { - return hasInitializer() ? cast<Expr>(SubExprs[Array]) : nullptr; + return hasInitializer() + ? cast<Expr>(getTrailingObjects<Stmt *>()[initExprOffset()]) + : nullptr; } /// Returns the CXXConstructExpr from this new-expression, or null. @@ -2027,15 +2105,13 @@ public: /// Indicates whether the required alignment should be implicitly passed to /// the allocation function. - bool passAlignment() const { - return PassAlignment; - } + bool passAlignment() const { return CXXNewExprBits.ShouldPassAlignment; } /// Answers whether the usual array deallocation function for the /// allocated type expects the size of the allocation as a /// parameter. bool doesUsualArrayDeleteWantSize() const { - return UsualArrayDeleteWantsSize; + return CXXNewExprBits.UsualArrayDeleteWantsSize; } using arg_iterator = ExprIterator; @@ -2050,103 +2126,85 @@ public: } arg_iterator placement_arg_begin() { - return SubExprs + Array + hasInitializer(); + return getTrailingObjects<Stmt *>() + placementNewArgsOffset(); } arg_iterator placement_arg_end() { - return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + return placement_arg_begin() + getNumPlacementArgs(); } const_arg_iterator placement_arg_begin() const { - return SubExprs + Array + hasInitializer(); + return getTrailingObjects<Stmt *>() + placementNewArgsOffset(); } const_arg_iterator placement_arg_end() const { - return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + return placement_arg_begin() + getNumPlacementArgs(); } using raw_arg_iterator = Stmt **; - raw_arg_iterator raw_arg_begin() { return SubExprs; } + raw_arg_iterator raw_arg_begin() { return getTrailingObjects<Stmt *>(); } raw_arg_iterator raw_arg_end() { - return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + return raw_arg_begin() + numTrailingObjects(OverloadToken<Stmt *>()); + } + const_arg_iterator raw_arg_begin() const { + return getTrailingObjects<Stmt *>(); } - const_arg_iterator raw_arg_begin() const { return SubExprs; } const_arg_iterator raw_arg_end() const { - return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + return raw_arg_begin() + numTrailingObjects(OverloadToken<Stmt *>()); } - SourceLocation getStartLoc() const { return Range.getBegin(); } + SourceLocation getBeginLoc() const { return Range.getBegin(); } SourceLocation getEndLoc() const { return Range.getEnd(); } SourceRange getDirectInitRange() const { return DirectInitRange; } - - SourceRange getSourceRange() const LLVM_READONLY { - return Range; - } - - SourceLocation getLocStart() const LLVM_READONLY { return getStartLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + SourceRange getSourceRange() const { return Range; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXNewExprClass; } // Iterators - child_range children() { - return child_range(raw_arg_begin(), raw_arg_end()); - } + child_range children() { return child_range(raw_arg_begin(), raw_arg_end()); } }; /// Represents a \c delete expression for memory deallocation and /// destructor calls, e.g. "delete[] pArray". class CXXDeleteExpr : public Expr { + friend class ASTStmtReader; + /// Points to the operator delete overload that is used. Could be a member. FunctionDecl *OperatorDelete = nullptr; /// The pointer expression to be deleted. Stmt *Argument = nullptr; - /// Location of the expression. - SourceLocation Loc; - - /// Is this a forced global delete, i.e. "::delete"? - bool GlobalDelete : 1; - - /// Is this the array form of delete, i.e. "delete[]"? - bool ArrayForm : 1; - - /// ArrayFormAsWritten can be different from ArrayForm if 'delete' is applied - /// to pointer-to-array type (ArrayFormAsWritten will be false while ArrayForm - /// will be true). - bool ArrayFormAsWritten : 1; - - /// Does the usual deallocation function for the element type require - /// a size_t argument? - bool UsualArrayDeleteWantsSize : 1; - public: - friend class ASTStmtReader; + CXXDeleteExpr(QualType Ty, bool GlobalDelete, bool ArrayForm, + bool ArrayFormAsWritten, bool UsualArrayDeleteWantsSize, + FunctionDecl *OperatorDelete, Expr *Arg, SourceLocation Loc) + : Expr(CXXDeleteExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + Arg->isInstantiationDependent(), + Arg->containsUnexpandedParameterPack()), + OperatorDelete(OperatorDelete), Argument(Arg) { + CXXDeleteExprBits.GlobalDelete = GlobalDelete; + CXXDeleteExprBits.ArrayForm = ArrayForm; + CXXDeleteExprBits.ArrayFormAsWritten = ArrayFormAsWritten; + CXXDeleteExprBits.UsualArrayDeleteWantsSize = UsualArrayDeleteWantsSize; + CXXDeleteExprBits.Loc = Loc; + } - CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm, - bool arrayFormAsWritten, bool usualArrayDeleteWantsSize, - FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc) - : Expr(CXXDeleteExprClass, ty, VK_RValue, OK_Ordinary, false, false, - arg->isInstantiationDependent(), - arg->containsUnexpandedParameterPack()), - OperatorDelete(operatorDelete), Argument(arg), Loc(loc), - GlobalDelete(globalDelete), - ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten), - UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) {} explicit CXXDeleteExpr(EmptyShell Shell) : Expr(CXXDeleteExprClass, Shell) {} - bool isGlobalDelete() const { return GlobalDelete; } - bool isArrayForm() const { return ArrayForm; } - bool isArrayFormAsWritten() const { return ArrayFormAsWritten; } + bool isGlobalDelete() const { return CXXDeleteExprBits.GlobalDelete; } + bool isArrayForm() const { return CXXDeleteExprBits.ArrayForm; } + bool isArrayFormAsWritten() const { + return CXXDeleteExprBits.ArrayFormAsWritten; + } /// Answers whether the usual array deallocation function for the /// allocated type expects the size of the allocation as a /// parameter. This can be true even if the actual deallocation /// function that we're using doesn't want a size. bool doesUsualArrayDeleteWantSize() const { - return UsualArrayDeleteWantsSize; + return CXXDeleteExprBits.UsualArrayDeleteWantsSize; } FunctionDecl *getOperatorDelete() const { return OperatorDelete; } @@ -2160,15 +2218,17 @@ public: /// be a pointer, return an invalid type. QualType getDestroyedType() const; - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY {return Argument->getLocEnd();} + SourceLocation getBeginLoc() const { return CXXDeleteExprBits.Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return Argument->getEndLoc(); + } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXDeleteExprClass; } // Iterators - child_range children() { return child_range(&Argument, &Argument+1); } + child_range children() { return child_range(&Argument, &Argument + 1); } }; /// Stores the type being destroyed by a pseudo-destructor expression. @@ -2346,8 +2406,10 @@ public: DestroyedType = PseudoDestructorTypeStorage(Info); } - SourceLocation getLocStart() const LLVM_READONLY {return Base->getLocStart();} - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY { + return Base->getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == CXXPseudoDestructorExprClass; @@ -2428,8 +2490,8 @@ public: getNumArgs()); } - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == TypeTraitExprClass; @@ -2468,8 +2530,6 @@ class ArrayTypeTraitExpr : public Expr { /// The type being queried. TypeSourceInfo *QueriedType = nullptr; - virtual void anchor(); - public: friend class ASTStmtReader; @@ -2487,10 +2547,8 @@ public: explicit ArrayTypeTraitExpr(EmptyShell Empty) : Expr(ArrayTypeTraitExprClass, Empty), ATT(0) {} - virtual ~ArrayTypeTraitExpr() = default; - - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParen; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParen; } ArrayTypeTrait getTrait() const { return static_cast<ArrayTypeTrait>(ATT); } @@ -2553,8 +2611,8 @@ public: explicit ExpressionTraitExpr(EmptyShell Empty) : Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false) {} - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParen; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParen; } ExpressionTrait getTrait() const { return static_cast<ExpressionTrait>(ET); } @@ -2575,58 +2633,54 @@ public: /// A reference to an overloaded function set, either an /// \c UnresolvedLookupExpr or an \c UnresolvedMemberExpr. class OverloadExpr : public Expr { + friend class ASTStmtReader; + friend class ASTStmtWriter; + /// The common name of these declarations. DeclarationNameInfo NameInfo; /// The nested-name-specifier that qualifies the name, if any. NestedNameSpecifierLoc QualifierLoc; - /// The results. These are undesugared, which is to say, they may - /// include UsingShadowDecls. Access is relative to the naming - /// class. - // FIXME: Allocate this data after the OverloadExpr subclass. - DeclAccessPair *Results = nullptr; - - unsigned NumResults = 0; - protected: - /// Whether the name includes info for explicit template - /// keyword and arguments. - bool HasTemplateKWAndArgsInfo = false; - - OverloadExpr(StmtClass K, const ASTContext &C, + OverloadExpr(StmtClass SC, const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End, - bool KnownDependent, - bool KnownInstantiationDependent, + bool KnownDependent, bool KnownInstantiationDependent, bool KnownContainsUnexpandedParameterPack); - OverloadExpr(StmtClass K, EmptyShell Empty) : Expr(K, Empty) {} + OverloadExpr(StmtClass SC, EmptyShell Empty, unsigned NumResults, + bool HasTemplateKWAndArgsInfo); - /// Return the optional template keyword and arguments info. - ASTTemplateKWAndArgsInfo * - getTrailingASTTemplateKWAndArgsInfo(); // defined far below. + /// Return the results. Defined after UnresolvedMemberExpr. + inline DeclAccessPair *getTrailingResults(); + const DeclAccessPair *getTrailingResults() const { + return const_cast<OverloadExpr *>(this)->getTrailingResults(); + } /// Return the optional template keyword and arguments info. + /// Defined after UnresolvedMemberExpr. + inline ASTTemplateKWAndArgsInfo *getTrailingASTTemplateKWAndArgsInfo(); const ASTTemplateKWAndArgsInfo *getTrailingASTTemplateKWAndArgsInfo() const { return const_cast<OverloadExpr *>(this) ->getTrailingASTTemplateKWAndArgsInfo(); } - /// Return the optional template arguments. - TemplateArgumentLoc *getTrailingTemplateArgumentLoc(); // defined far below + /// Return the optional template arguments. Defined after + /// UnresolvedMemberExpr. + inline TemplateArgumentLoc *getTrailingTemplateArgumentLoc(); + const TemplateArgumentLoc *getTrailingTemplateArgumentLoc() const { + return const_cast<OverloadExpr *>(this)->getTrailingTemplateArgumentLoc(); + } - void initializeResults(const ASTContext &C, - UnresolvedSetIterator Begin, - UnresolvedSetIterator End); + bool hasTemplateKWAndArgsInfo() const { + return OverloadExprBits.HasTemplateKWAndArgsInfo; + } public: - friend class ASTStmtReader; - friend class ASTStmtWriter; - struct FindResult { OverloadExpr *Expression; bool IsAddressOfOperand; @@ -2662,20 +2716,26 @@ public: } /// Gets the naming class of this lookup, if any. - CXXRecordDecl *getNamingClass() const; + /// Defined after UnresolvedMemberExpr. + inline CXXRecordDecl *getNamingClass(); + const CXXRecordDecl *getNamingClass() const { + return const_cast<OverloadExpr *>(this)->getNamingClass(); + } using decls_iterator = UnresolvedSetImpl::iterator; - decls_iterator decls_begin() const { return UnresolvedSetIterator(Results); } + decls_iterator decls_begin() const { + return UnresolvedSetIterator(getTrailingResults()); + } decls_iterator decls_end() const { - return UnresolvedSetIterator(Results + NumResults); + return UnresolvedSetIterator(getTrailingResults() + getNumDecls()); } llvm::iterator_range<decls_iterator> decls() const { return llvm::make_range(decls_begin(), decls_end()); } /// Gets the number of declarations in the unresolved set. - unsigned getNumDecls() const { return NumResults; } + unsigned getNumDecls() const { return OverloadExprBits.NumResults; } /// Gets the full name info. const DeclarationNameInfo &getNameInfo() const { return NameInfo; } @@ -2698,21 +2758,24 @@ public: /// Retrieve the location of the template keyword preceding /// this name, if any. SourceLocation getTemplateKeywordLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingASTTemplateKWAndArgsInfo()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the name, if any. SourceLocation getLAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingASTTemplateKWAndArgsInfo()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the name, if any. SourceLocation getRAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingASTTemplateKWAndArgsInfo()->RAngleLoc; } @@ -2764,97 +2827,93 @@ public: /// members and therefore appear only in UnresolvedMemberLookupExprs. class UnresolvedLookupExpr final : public OverloadExpr, - private llvm::TrailingObjects< - UnresolvedLookupExpr, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { + private llvm::TrailingObjects<UnresolvedLookupExpr, DeclAccessPair, + ASTTemplateKWAndArgsInfo, + TemplateArgumentLoc> { friend class ASTStmtReader; friend class OverloadExpr; friend TrailingObjects; - /// True if these lookup results should be extended by - /// argument-dependent lookup if this is the operand of a function - /// call. - bool RequiresADL = false; - - /// True if these lookup results are overloaded. This is pretty - /// trivially rederivable if we urgently need to kill this field. - bool Overloaded = false; - /// The naming class (C++ [class.access.base]p5) of the lookup, if /// any. This can generally be recalculated from the context chain, - /// but that can be fairly expensive for unqualified lookups. If we - /// want to improve memory use here, this could go in a union - /// against the qualified-lookup bits. - CXXRecordDecl *NamingClass = nullptr; + /// but that can be fairly expensive for unqualified lookups. + CXXRecordDecl *NamingClass; + + // UnresolvedLookupExpr is followed by several trailing objects. + // They are in order: + // + // * An array of getNumResults() DeclAccessPair for the results. These are + // undesugared, which is to say, they may include UsingShadowDecls. + // Access is relative to the naming class. + // + // * An optional ASTTemplateKWAndArgsInfo for the explicitly specified + // template keyword and arguments. Present if and only if + // hasTemplateKWAndArgsInfo(). + // + // * An array of getNumTemplateArgs() TemplateArgumentLoc containing + // location information for the explicitly specified template arguments. - UnresolvedLookupExpr(const ASTContext &C, - CXXRecordDecl *NamingClass, + UnresolvedLookupExpr(const ASTContext &Context, CXXRecordDecl *NamingClass, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, - const DeclarationNameInfo &NameInfo, - bool RequiresADL, bool Overloaded, + const DeclarationNameInfo &NameInfo, bool RequiresADL, + bool Overloaded, const TemplateArgumentListInfo *TemplateArgs, - UnresolvedSetIterator Begin, UnresolvedSetIterator End) - : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc, - NameInfo, TemplateArgs, Begin, End, false, false, false), - RequiresADL(RequiresADL), - Overloaded(Overloaded), NamingClass(NamingClass) {} + UnresolvedSetIterator Begin, UnresolvedSetIterator End); - UnresolvedLookupExpr(EmptyShell Empty) - : OverloadExpr(UnresolvedLookupExprClass, Empty) {} + UnresolvedLookupExpr(EmptyShell Empty, unsigned NumResults, + bool HasTemplateKWAndArgsInfo); - size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { - return HasTemplateKWAndArgsInfo ? 1 : 0; + unsigned numTrailingObjects(OverloadToken<DeclAccessPair>) const { + return getNumDecls(); } -public: - static UnresolvedLookupExpr *Create(const ASTContext &C, - CXXRecordDecl *NamingClass, - NestedNameSpecifierLoc QualifierLoc, - const DeclarationNameInfo &NameInfo, - bool ADL, bool Overloaded, - UnresolvedSetIterator Begin, - UnresolvedSetIterator End) { - return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, - SourceLocation(), NameInfo, - ADL, Overloaded, nullptr, Begin, End); + unsigned numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return hasTemplateKWAndArgsInfo(); } - static UnresolvedLookupExpr *Create(const ASTContext &C, - CXXRecordDecl *NamingClass, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - const DeclarationNameInfo &NameInfo, - bool ADL, - const TemplateArgumentListInfo *Args, - UnresolvedSetIterator Begin, - UnresolvedSetIterator End); +public: + static UnresolvedLookupExpr * + Create(const ASTContext &Context, CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded, + UnresolvedSetIterator Begin, UnresolvedSetIterator End); + + static UnresolvedLookupExpr * + Create(const ASTContext &Context, CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, bool RequiresADL, + const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin, + UnresolvedSetIterator End); - static UnresolvedLookupExpr *CreateEmpty(const ASTContext &C, + static UnresolvedLookupExpr *CreateEmpty(const ASTContext &Context, + unsigned NumResults, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs); /// True if this declaration should be extended by /// argument-dependent lookup. - bool requiresADL() const { return RequiresADL; } + bool requiresADL() const { return UnresolvedLookupExprBits.RequiresADL; } /// True if this lookup is overloaded. - bool isOverloaded() const { return Overloaded; } + bool isOverloaded() const { return UnresolvedLookupExprBits.Overloaded; } /// Gets the 'naming class' (in the sense of C++0x /// [class.access.base]p5) of the lookup. This is the scope /// that was looked in to find these results. - CXXRecordDecl *getNamingClass() const { return NamingClass; } + CXXRecordDecl *getNamingClass() { return NamingClass; } + const CXXRecordDecl *getNamingClass() const { return NamingClass; } - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getBeginLoc() const LLVM_READONLY { if (NestedNameSpecifierLoc l = getQualifierLoc()) return l.getBeginLoc(); - return getNameInfo().getLocStart(); + return getNameInfo().getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { if (hasExplicitTemplateArgs()) return getRAngleLoc(); - return getNameInfo().getLocEnd(); + return getNameInfo().getEndLoc(); } child_range children() { @@ -2885,6 +2944,10 @@ class DependentScopeDeclRefExpr final private llvm::TrailingObjects<DependentScopeDeclRefExpr, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + /// The nested-name-specifier that qualifies this unresolved /// declaration name. NestedNameSpecifierLoc QualifierLoc; @@ -2892,32 +2955,26 @@ class DependentScopeDeclRefExpr final /// The name of the entity we will be referencing. DeclarationNameInfo NameInfo; - /// Whether the name includes info for explicit template - /// keyword and arguments. - bool HasTemplateKWAndArgsInfo; - - DependentScopeDeclRefExpr(QualType T, - NestedNameSpecifierLoc QualifierLoc, + DependentScopeDeclRefExpr(QualType Ty, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *Args); size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { - return HasTemplateKWAndArgsInfo ? 1 : 0; + return hasTemplateKWAndArgsInfo(); } -public: - friend class ASTStmtReader; - friend class ASTStmtWriter; - friend TrailingObjects; + bool hasTemplateKWAndArgsInfo() const { + return DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo; + } - static DependentScopeDeclRefExpr *Create(const ASTContext &C, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs); +public: + static DependentScopeDeclRefExpr * + Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); - static DependentScopeDeclRefExpr *CreateEmpty(const ASTContext &C, + static DependentScopeDeclRefExpr *CreateEmpty(const ASTContext &Context, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs); @@ -2945,21 +3002,24 @@ public: /// Retrieve the location of the template keyword preceding /// this name, if any. SourceLocation getTemplateKeywordLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the name, if any. SourceLocation getLAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the name, if any. SourceLocation getRAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc; } @@ -2995,13 +3055,13 @@ public: return {getTemplateArgs(), getNumTemplateArgs()}; } - /// Note: getLocStart() is the start of the whole DependentScopeDeclRefExpr, + /// Note: getBeginLoc() is the start of the whole DependentScopeDeclRefExpr, /// and differs from getLocation().getStart(). - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getBeginLoc() const LLVM_READONLY { return QualifierLoc.getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { if (hasExplicitTemplateArgs()) return getRAngleLoc(); return getLocation(); @@ -3027,7 +3087,7 @@ public: /// potentially-evaluated block literal. The lifetime of a block /// literal is the extent of the enclosing scope. class ExprWithCleanups final - : public Expr, + : public FullExpr, private llvm::TrailingObjects<ExprWithCleanups, BlockDecl *> { public: /// The type of objects that are kept in the cleanup. @@ -3040,8 +3100,6 @@ private: friend class ASTStmtReader; friend TrailingObjects; - Stmt *SubExpr; - ExprWithCleanups(EmptyShell, unsigned NumObjects); ExprWithCleanups(Expr *SubExpr, bool CleanupsHaveSideEffects, ArrayRef<CleanupObject> Objects); @@ -3066,22 +3124,17 @@ public: return getObjects()[i]; } - Expr *getSubExpr() { return cast<Expr>(SubExpr); } - const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } - bool cleanupsHaveSideEffects() const { return ExprWithCleanupsBits.CleanupsHaveSideEffects; } - /// As with any mutator of the AST, be very careful - /// when modifying an existing AST to preserve its invariants. - void setSubExpr(Expr *E) { SubExpr = E; } - - SourceLocation getLocStart() const LLVM_READONLY { - return SubExpr->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return SubExpr->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd();} + SourceLocation getEndLoc() const LLVM_READONLY { + return SubExpr->getEndLoc(); + } // Implement isa/cast/dyncast/etc. static bool classof(const Stmt *T) { @@ -3120,7 +3173,7 @@ class CXXUnresolvedConstructExpr final friend TrailingObjects; /// The type being constructed. - TypeSourceInfo *Type = nullptr; + TypeSourceInfo *TSI; /// The location of the left parentheses ('('). SourceLocation LParenLoc; @@ -3128,34 +3181,31 @@ class CXXUnresolvedConstructExpr final /// The location of the right parentheses (')'). SourceLocation RParenLoc; - /// The number of arguments used to construct the type. - unsigned NumArgs; - - CXXUnresolvedConstructExpr(TypeSourceInfo *Type, - SourceLocation LParenLoc, - ArrayRef<Expr*> Args, - SourceLocation RParenLoc); + CXXUnresolvedConstructExpr(TypeSourceInfo *TSI, SourceLocation LParenLoc, + ArrayRef<Expr *> Args, SourceLocation RParenLoc); CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs) - : Expr(CXXUnresolvedConstructExprClass, Empty), NumArgs(NumArgs) {} + : Expr(CXXUnresolvedConstructExprClass, Empty) { + CXXUnresolvedConstructExprBits.NumArgs = NumArgs; + } public: - static CXXUnresolvedConstructExpr *Create(const ASTContext &C, + static CXXUnresolvedConstructExpr *Create(const ASTContext &Context, TypeSourceInfo *Type, SourceLocation LParenLoc, - ArrayRef<Expr*> Args, + ArrayRef<Expr *> Args, SourceLocation RParenLoc); - static CXXUnresolvedConstructExpr *CreateEmpty(const ASTContext &C, + static CXXUnresolvedConstructExpr *CreateEmpty(const ASTContext &Context, unsigned NumArgs); /// Retrieve the type that is being constructed, as specified /// in the source code. - QualType getTypeAsWritten() const { return Type->getType(); } + QualType getTypeAsWritten() const { return TSI->getType(); } /// Retrieve the type source information for the type being /// constructed. - TypeSourceInfo *getTypeSourceInfo() const { return Type; } + TypeSourceInfo *getTypeSourceInfo() const { return TSI; } /// Retrieve the location of the left parentheses ('(') that /// precedes the argument list. @@ -3173,40 +3223,43 @@ public: bool isListInitialization() const { return LParenLoc.isInvalid(); } /// Retrieve the number of arguments. - unsigned arg_size() const { return NumArgs; } + unsigned arg_size() const { return CXXUnresolvedConstructExprBits.NumArgs; } using arg_iterator = Expr **; + using arg_range = llvm::iterator_range<arg_iterator>; arg_iterator arg_begin() { return getTrailingObjects<Expr *>(); } - arg_iterator arg_end() { return arg_begin() + NumArgs; } + arg_iterator arg_end() { return arg_begin() + arg_size(); } + arg_range arguments() { return arg_range(arg_begin(), arg_end()); } using const_arg_iterator = const Expr* const *; + using const_arg_range = llvm::iterator_range<const_arg_iterator>; const_arg_iterator arg_begin() const { return getTrailingObjects<Expr *>(); } - const_arg_iterator arg_end() const { - return arg_begin() + NumArgs; + const_arg_iterator arg_end() const { return arg_begin() + arg_size(); } + const_arg_range arguments() const { + return const_arg_range(arg_begin(), arg_end()); } Expr *getArg(unsigned I) { - assert(I < NumArgs && "Argument index out-of-range"); - return *(arg_begin() + I); + assert(I < arg_size() && "Argument index out-of-range"); + return arg_begin()[I]; } const Expr *getArg(unsigned I) const { - assert(I < NumArgs && "Argument index out-of-range"); - return *(arg_begin() + I); + assert(I < arg_size() && "Argument index out-of-range"); + return arg_begin()[I]; } void setArg(unsigned I, Expr *E) { - assert(I < NumArgs && "Argument index out-of-range"); - *(arg_begin() + I) = E; + assert(I < arg_size() && "Argument index out-of-range"); + arg_begin()[I] = E; } - SourceLocation getLocStart() const LLVM_READONLY; - - SourceLocation getLocEnd() const LLVM_READONLY { - if (!RParenLoc.isValid() && NumArgs > 0) - return getArg(NumArgs - 1)->getLocEnd(); + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY { + if (!RParenLoc.isValid() && arg_size() > 0) + return getArg(arg_size() - 1)->getEndLoc(); return RParenLoc; } @@ -3217,7 +3270,7 @@ public: // Iterators child_range children() { auto **begin = reinterpret_cast<Stmt **>(arg_begin()); - return child_range(begin, begin + NumArgs); + return child_range(begin, begin + arg_size()); } }; @@ -3232,7 +3285,11 @@ class CXXDependentScopeMemberExpr final : public Expr, private llvm::TrailingObjects<CXXDependentScopeMemberExpr, ASTTemplateKWAndArgsInfo, - TemplateArgumentLoc> { + TemplateArgumentLoc, NamedDecl *> { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend TrailingObjects; + /// The expression for the base pointer or class reference, /// e.g., the \c x in x.f. Can be null in implicit accesses. Stmt *Base; @@ -3241,40 +3298,53 @@ class CXXDependentScopeMemberExpr final /// implicit accesses. QualType BaseType; - /// Whether this member expression used the '->' operator or - /// the '.' operator. - bool IsArrow : 1; - - /// Whether this member expression has info for explicit template - /// keyword and arguments. - bool HasTemplateKWAndArgsInfo : 1; - - /// The location of the '->' or '.' operator. - SourceLocation OperatorLoc; - /// The nested-name-specifier that precedes the member name, if any. + /// FIXME: This could be in principle store as a trailing object. + /// However the performance impact of doing so should be investigated first. NestedNameSpecifierLoc QualifierLoc; - /// In a qualified member access expression such as t->Base::f, this - /// member stores the resolves of name lookup in the context of the member - /// access expression, to be used at instantiation time. - /// - /// FIXME: This member, along with the QualifierLoc, could - /// be stuck into a structure that is optionally allocated at the end of - /// the CXXDependentScopeMemberExpr, to save space in the common case. - NamedDecl *FirstQualifierFoundInScope; - /// The member to which this member expression refers, which /// can be name, overloaded operator, or destructor. /// /// FIXME: could also be a template-id DeclarationNameInfo MemberNameInfo; - size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { - return HasTemplateKWAndArgsInfo ? 1 : 0; + // CXXDependentScopeMemberExpr is followed by several trailing objects, + // some of which optional. They are in order: + // + // * An optional ASTTemplateKWAndArgsInfo for the explicitly specified + // template keyword and arguments. Present if and only if + // hasTemplateKWAndArgsInfo(). + // + // * An array of getNumTemplateArgs() TemplateArgumentLoc containing location + // information for the explicitly specified template arguments. + // + // * An optional NamedDecl *. In a qualified member access expression such + // as t->Base::f, this member stores the resolves of name lookup in the + // context of the member access expression, to be used at instantiation + // time. Present if and only if hasFirstQualifierFoundInScope(). + + bool hasTemplateKWAndArgsInfo() const { + return CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo; } - CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, + bool hasFirstQualifierFoundInScope() const { + return CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope; + } + + unsigned numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return hasTemplateKWAndArgsInfo(); + } + + unsigned numTrailingObjects(OverloadToken<TemplateArgumentLoc>) const { + return getNumTemplateArgs(); + } + + unsigned numTrailingObjects(OverloadToken<NamedDecl *>) const { + return hasFirstQualifierFoundInScope(); + } + + CXXDependentScopeMemberExpr(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, @@ -3283,33 +3353,29 @@ class CXXDependentScopeMemberExpr final DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs); -public: - friend class ASTStmtReader; - friend class ASTStmtWriter; - friend TrailingObjects; - - CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, - QualType BaseType, bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifierLoc QualifierLoc, - NamedDecl *FirstQualifierFoundInScope, - DeclarationNameInfo MemberNameInfo); + CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasTemplateKWAndArgsInfo, + bool HasFirstQualifierFoundInScope); +public: static CXXDependentScopeMemberExpr * - Create(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, + Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs); static CXXDependentScopeMemberExpr * - CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, - unsigned NumTemplateArgs); + CreateEmpty(const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope); /// True if this is an implicit access, i.e. one in which the /// member being accessed was not written in the source. The source /// location of the operator is invalid in this case. - bool isImplicitAccess() const; + bool isImplicitAccess() const { + if (!Base) + return true; + return cast<Expr>(Base)->isImplicitCXXThis(); + } /// Retrieve the base object of this member expressions, /// e.g., the \c x in \c x.m. @@ -3322,13 +3388,14 @@ public: /// Determine whether this member expression used the '->' /// operator; otherwise, it used the '.' operator. - bool isArrow() const { return IsArrow; } + bool isArrow() const { return CXXDependentScopeMemberExprBits.IsArrow; } /// Retrieve the location of the '->' or '.' operator. - SourceLocation getOperatorLoc() const { return OperatorLoc; } + SourceLocation getOperatorLoc() const { + return CXXDependentScopeMemberExprBits.OperatorLoc; + } - /// Retrieve the nested-name-specifier that qualifies the member - /// name. + /// Retrieve the nested-name-specifier that qualifies the member name. NestedNameSpecifier *getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3349,17 +3416,17 @@ public: /// combined with the results of name lookup into the type of the object /// expression itself (the class type of x). NamedDecl *getFirstQualifierFoundInScope() const { - return FirstQualifierFoundInScope; + if (!hasFirstQualifierFoundInScope()) + return nullptr; + return *getTrailingObjects<NamedDecl *>(); } - /// Retrieve the name of the member that this expression - /// refers to. + /// Retrieve the name of the member that this expression refers to. const DeclarationNameInfo &getMemberNameInfo() const { return MemberNameInfo; } - /// Retrieve the name of the member that this expression - /// refers to. + /// Retrieve the name of the member that this expression refers to. DeclarationName getMember() const { return MemberNameInfo.getName(); } // Retrieve the location of the name of the member that this @@ -3369,21 +3436,24 @@ public: /// Retrieve the location of the template keyword preceding the /// member name, if any. SourceLocation getTemplateKeywordLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the member name, if any. SourceLocation getLAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the member name, if any. SourceLocation getRAngleLoc() const { - if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + if (!hasTemplateKWAndArgsInfo()) + return SourceLocation(); return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc; } @@ -3424,15 +3494,15 @@ public: return {getTemplateArgs(), getNumTemplateArgs()}; } - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getBeginLoc() const LLVM_READONLY { if (!isImplicitAccess()) - return Base->getLocStart(); + return Base->getBeginLoc(); if (getQualifier()) return getQualifierLoc().getBeginLoc(); return MemberNameInfo.getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { if (hasExplicitTemplateArgs()) return getRAngleLoc(); return MemberNameInfo.getEndLoc(); @@ -3467,25 +3537,18 @@ public: /// DeclRefExpr, depending on whether the member is static. class UnresolvedMemberExpr final : public OverloadExpr, - private llvm::TrailingObjects< - UnresolvedMemberExpr, ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { + private llvm::TrailingObjects<UnresolvedMemberExpr, DeclAccessPair, + ASTTemplateKWAndArgsInfo, + TemplateArgumentLoc> { friend class ASTStmtReader; friend class OverloadExpr; friend TrailingObjects; - /// Whether this member expression used the '->' operator or - /// the '.' operator. - bool IsArrow : 1; - - /// Whether the lookup results contain an unresolved using - /// declaration. - bool HasUnresolvedUsing : 1; - /// The expression for the base pointer or class reference, /// e.g., the \c x in x.f. /// /// This can be null if this is an 'unbased' member expression. - Stmt *Base = nullptr; + Stmt *Base; /// The type of the base expression; never null. QualType BaseType; @@ -3493,7 +3556,21 @@ class UnresolvedMemberExpr final /// The location of the '->' or '.' operator. SourceLocation OperatorLoc; - UnresolvedMemberExpr(const ASTContext &C, bool HasUnresolvedUsing, + // UnresolvedMemberExpr is followed by several trailing objects. + // They are in order: + // + // * An array of getNumResults() DeclAccessPair for the results. These are + // undesugared, which is to say, they may include UsingShadowDecls. + // Access is relative to the naming class. + // + // * An optional ASTTemplateKWAndArgsInfo for the explicitly specified + // template keyword and arguments. Present if and only if + // hasTemplateKWAndArgsInfo(). + // + // * An array of getNumTemplateArgs() TemplateArgumentLoc containing + // location information for the explicitly specified template arguments. + + UnresolvedMemberExpr(const ASTContext &Context, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, @@ -3502,28 +3579,30 @@ class UnresolvedMemberExpr final const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End); - UnresolvedMemberExpr(EmptyShell Empty) - : OverloadExpr(UnresolvedMemberExprClass, Empty), IsArrow(false), - HasUnresolvedUsing(false) {} + UnresolvedMemberExpr(EmptyShell Empty, unsigned NumResults, + bool HasTemplateKWAndArgsInfo); - size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { - return HasTemplateKWAndArgsInfo ? 1 : 0; + unsigned numTrailingObjects(OverloadToken<DeclAccessPair>) const { + return getNumDecls(); + } + + unsigned numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { + return hasTemplateKWAndArgsInfo(); } public: static UnresolvedMemberExpr * - Create(const ASTContext &C, bool HasUnresolvedUsing, - Expr *Base, QualType BaseType, bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, + Create(const ASTContext &Context, bool HasUnresolvedUsing, Expr *Base, + QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End); - static UnresolvedMemberExpr * - CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, - unsigned NumTemplateArgs); + static UnresolvedMemberExpr *CreateEmpty(const ASTContext &Context, + unsigned NumResults, + bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); /// True if this is an implicit access, i.e., one in which the /// member being accessed was not written in the source. @@ -3546,46 +3625,50 @@ public: /// Determine whether the lookup results contain an unresolved using /// declaration. - bool hasUnresolvedUsing() const { return HasUnresolvedUsing; } + bool hasUnresolvedUsing() const { + return UnresolvedMemberExprBits.HasUnresolvedUsing; + } /// Determine whether this member expression used the '->' /// operator; otherwise, it used the '.' operator. - bool isArrow() const { return IsArrow; } + bool isArrow() const { return UnresolvedMemberExprBits.IsArrow; } /// Retrieve the location of the '->' or '.' operator. SourceLocation getOperatorLoc() const { return OperatorLoc; } /// Retrieve the naming class of this lookup. - CXXRecordDecl *getNamingClass() const; + CXXRecordDecl *getNamingClass(); + const CXXRecordDecl *getNamingClass() const { + return const_cast<UnresolvedMemberExpr *>(this)->getNamingClass(); + } /// Retrieve the full name info for the member that this expression /// refers to. const DeclarationNameInfo &getMemberNameInfo() const { return getNameInfo(); } - /// Retrieve the name of the member that this expression - /// refers to. + /// Retrieve the name of the member that this expression refers to. DeclarationName getMemberName() const { return getName(); } - // Retrieve the location of the name of the member that this - // expression refers to. + /// Retrieve the location of the name of the member that this + /// expression refers to. SourceLocation getMemberLoc() const { return getNameLoc(); } - // Return the preferred location (the member name) for the arrow when - // diagnosing a problem with this expression. + /// Return the preferred location (the member name) for the arrow when + /// diagnosing a problem with this expression. SourceLocation getExprLoc() const LLVM_READONLY { return getMemberLoc(); } - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getBeginLoc() const LLVM_READONLY { if (!isImplicitAccess()) - return Base->getLocStart(); + return Base->getBeginLoc(); if (NestedNameSpecifierLoc l = getQualifierLoc()) return l.getBeginLoc(); - return getMemberNameInfo().getLocStart(); + return getMemberNameInfo().getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getEndLoc() const LLVM_READONLY { if (hasExplicitTemplateArgs()) return getRAngleLoc(); - return getMemberNameInfo().getLocEnd(); + return getMemberNameInfo().getEndLoc(); } static bool classof(const Stmt *T) { @@ -3600,26 +3683,33 @@ public: } }; -inline ASTTemplateKWAndArgsInfo * -OverloadExpr::getTrailingASTTemplateKWAndArgsInfo() { - if (!HasTemplateKWAndArgsInfo) +DeclAccessPair *OverloadExpr::getTrailingResults() { + if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(this)) + return ULE->getTrailingObjects<DeclAccessPair>(); + return cast<UnresolvedMemberExpr>(this)->getTrailingObjects<DeclAccessPair>(); +} + +ASTTemplateKWAndArgsInfo *OverloadExpr::getTrailingASTTemplateKWAndArgsInfo() { + if (!hasTemplateKWAndArgsInfo()) return nullptr; - if (isa<UnresolvedLookupExpr>(this)) - return cast<UnresolvedLookupExpr>(this) - ->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); - else - return cast<UnresolvedMemberExpr>(this) - ->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); + if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(this)) + return ULE->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); + return cast<UnresolvedMemberExpr>(this) + ->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); +} + +TemplateArgumentLoc *OverloadExpr::getTrailingTemplateArgumentLoc() { + if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(this)) + return ULE->getTrailingObjects<TemplateArgumentLoc>(); + return cast<UnresolvedMemberExpr>(this) + ->getTrailingObjects<TemplateArgumentLoc>(); } -inline TemplateArgumentLoc *OverloadExpr::getTrailingTemplateArgumentLoc() { - if (isa<UnresolvedLookupExpr>(this)) - return cast<UnresolvedLookupExpr>(this) - ->getTrailingObjects<TemplateArgumentLoc>(); - else - return cast<UnresolvedMemberExpr>(this) - ->getTrailingObjects<TemplateArgumentLoc>(); +CXXRecordDecl *OverloadExpr::getNamingClass() { + if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(this)) + return ULE->getNamingClass(); + return cast<UnresolvedMemberExpr>(this)->getNamingClass(); } /// Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]). @@ -3629,7 +3719,6 @@ inline TemplateArgumentLoc *OverloadExpr::getTrailingTemplateArgumentLoc() { class CXXNoexceptExpr : public Expr { friend class ASTStmtReader; - bool Value : 1; Stmt *Operand; SourceRange Range; @@ -3637,21 +3726,23 @@ public: CXXNoexceptExpr(QualType Ty, Expr *Operand, CanThrowResult Val, SourceLocation Keyword, SourceLocation RParen) : Expr(CXXNoexceptExprClass, Ty, VK_RValue, OK_Ordinary, - /*TypeDependent*/false, - /*ValueDependent*/Val == CT_Dependent, + /*TypeDependent*/ false, + /*ValueDependent*/ Val == CT_Dependent, Val == CT_Dependent || Operand->isInstantiationDependent(), Operand->containsUnexpandedParameterPack()), - Value(Val == CT_Cannot), Operand(Operand), Range(Keyword, RParen) {} + Operand(Operand), Range(Keyword, RParen) { + CXXNoexceptExprBits.Value = Val == CT_Cannot; + } CXXNoexceptExpr(EmptyShell Empty) : Expr(CXXNoexceptExprClass, Empty) {} - Expr *getOperand() const { return static_cast<Expr*>(Operand); } + Expr *getOperand() const { return static_cast<Expr *>(Operand); } - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } - SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getBeginLoc() const { return Range.getBegin(); } + SourceLocation getEndLoc() const { return Range.getEnd(); } + SourceRange getSourceRange() const { return Range; } - bool getValue() const { return Value; } + bool getValue() const { return CXXNoexceptExprBits.Value; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXNoexceptExprClass; @@ -3725,11 +3816,11 @@ public: return None; } - SourceLocation getLocStart() const LLVM_READONLY { - return Pattern->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return Pattern->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return EllipsisLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return EllipsisLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == PackExpansionExprClass; @@ -3849,8 +3940,8 @@ public: return llvm::makeArrayRef(Args, Args + Length); } - SourceLocation getLocStart() const LLVM_READONLY { return OperatorLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return OperatorLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == SizeOfPackExprClass; @@ -3874,27 +3965,27 @@ class SubstNonTypeTemplateParmExpr : public Expr { /// The replacement expression. Stmt *Replacement; - /// The location of the non-type template parameter reference. - SourceLocation NameLoc; - explicit SubstNonTypeTemplateParmExpr(EmptyShell Empty) : Expr(SubstNonTypeTemplateParmExprClass, Empty) {} public: - SubstNonTypeTemplateParmExpr(QualType type, - ExprValueKind valueKind, - SourceLocation loc, - NonTypeTemplateParmDecl *param, - Expr *replacement) - : Expr(SubstNonTypeTemplateParmExprClass, type, valueKind, OK_Ordinary, - replacement->isTypeDependent(), replacement->isValueDependent(), - replacement->isInstantiationDependent(), - replacement->containsUnexpandedParameterPack()), - Param(param), Replacement(replacement), NameLoc(loc) {} + SubstNonTypeTemplateParmExpr(QualType Ty, ExprValueKind ValueKind, + SourceLocation Loc, + NonTypeTemplateParmDecl *Param, + Expr *Replacement) + : Expr(SubstNonTypeTemplateParmExprClass, Ty, ValueKind, OK_Ordinary, + Replacement->isTypeDependent(), Replacement->isValueDependent(), + Replacement->isInstantiationDependent(), + Replacement->containsUnexpandedParameterPack()), + Param(Param), Replacement(Replacement) { + SubstNonTypeTemplateParmExprBits.NameLoc = Loc; + } - SourceLocation getNameLoc() const { return NameLoc; } - SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return NameLoc; } + SourceLocation getNameLoc() const { + return SubstNonTypeTemplateParmExprBits.NameLoc; + } + SourceLocation getBeginLoc() const { return getNameLoc(); } + SourceLocation getEndLoc() const { return getNameLoc(); } Expr *getReplacement() const { return cast<Expr>(Replacement); } @@ -3905,7 +3996,7 @@ public: } // Iterators - child_range children() { return child_range(&Replacement, &Replacement+1); } + child_range children() { return child_range(&Replacement, &Replacement + 1); } }; /// Represents a reference to a non-type template parameter pack that @@ -3957,8 +4048,8 @@ public: /// template arguments. TemplateArgument getArgumentPack() const; - SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return NameLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return NameLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return NameLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass; @@ -4030,8 +4121,8 @@ public: /// Get an expansion of the parameter pack by index. ParmVarDecl *getExpansion(unsigned I) const { return begin()[I]; } - SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return NameLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return NameLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return NameLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == FunctionParmPackExprClass; @@ -4142,12 +4233,12 @@ public: return getValueKind() == VK_LValue; } - SourceLocation getLocStart() const LLVM_READONLY { - return getTemporary()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getTemporary()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return getTemporary()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getTemporary()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -4217,13 +4308,9 @@ public: SourceLocation getEllipsisLoc() const { return EllipsisLoc; } BinaryOperatorKind getOperator() const { return Opcode; } - SourceLocation getLocStart() const LLVM_READONLY { - return LParenLoc; - } + SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return RParenLoc; - } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXFoldExprClass; @@ -4312,12 +4399,10 @@ public: return static_cast<Expr*>(SubExprs[SubExpr::Resume]); } - SourceLocation getLocStart() const LLVM_READONLY { - return KeywordLoc; - } + SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return getCommonExpr()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getCommonExpr()->getEndLoc(); } child_range children() { @@ -4400,10 +4485,10 @@ public: SourceLocation getKeywordLoc() const { return KeywordLoc; } - SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return getOperand()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getOperand()->getEndLoc(); } child_range children() { return child_range(SubExprs, SubExprs + 2); } diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index bb0402c27080..c7b305f3304e 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -67,8 +67,8 @@ public: SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return String->getLocEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return String->getEndLoc(); } // Iterators child_range children() { return child_range(&String, &String+1); } @@ -94,8 +94,8 @@ public: bool getValue() const { return Value; } void setValue(bool V) { Value = V; } - SourceLocation getLocStart() const LLVM_READONLY { return Loc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } @@ -141,8 +141,8 @@ public: SourceLocation getAtLoc() const { return Range.getBegin(); } - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } SourceRange getSourceRange() const LLVM_READONLY { return Range; @@ -194,8 +194,8 @@ public: static ObjCArrayLiteral *CreateEmpty(const ASTContext &C, unsigned NumElements); - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } SourceRange getSourceRange() const LLVM_READONLY { return Range; } /// Retrieve elements of array of literals. @@ -359,8 +359,8 @@ public: return DictWithObjectsMethod; } - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } SourceRange getSourceRange() const LLVM_READONLY { return Range; } // Iterators @@ -412,8 +412,8 @@ public: EncodedType = EncType; } - SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } // Iterators child_range children() { @@ -447,8 +447,8 @@ public: void setAtLoc(SourceLocation L) { AtLoc = L; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } /// getNumArgs - Return the number of actual arguments to this call. unsigned getNumArgs() const { return SelName.getNumArgs(); } @@ -496,8 +496,8 @@ public: void setAtLoc(SourceLocation L) { AtLoc = L; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } // Iterators child_range children() { @@ -556,10 +556,10 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - SourceLocation getLocStart() const LLVM_READONLY { - return isFreeIvar() ? Loc : getBase()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return isFreeIvar() ? Loc : getBase()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } SourceLocation getOpLoc() const { return OpLoc; } void setOpLoc(SourceLocation L) { OpLoc = L; } @@ -742,11 +742,12 @@ public: /// Determine the type of the base, regardless of the kind of receiver. QualType getReceiverType(const ASTContext &ctx) const; - SourceLocation getLocStart() const LLVM_READONLY { - return isObjectReceiver() ? getBase()->getLocStart() :getReceiverLocation(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return isObjectReceiver() ? getBase()->getBeginLoc() + : getReceiverLocation(); } - SourceLocation getLocEnd() const LLVM_READONLY { return IdLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return IdLoc; } // Iterators child_range children() { @@ -838,11 +839,11 @@ public: SourceLocation getRBracket() const { return RBracket; } void setRBracket(SourceLocation RB) { RBracket = RB; } - SourceLocation getLocStart() const LLVM_READONLY { - return SubExprs[BASE]->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return SubExprs[BASE]->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return RBracket; } + SourceLocation getEndLoc() const LLVM_READONLY { return RBracket; } Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); } void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; } @@ -1364,7 +1365,7 @@ public: SourceLocation getSelectorStartLoc() const { if (isImplicit()) - return getLocStart(); + return getBeginLoc(); return getSelectorLoc(0); } @@ -1395,8 +1396,8 @@ public: RBracLoc = R.getEnd(); } - SourceLocation getLocStart() const LLVM_READONLY { return LBracLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RBracLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return LBracLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RBracLoc; } // Iterators child_range children(); @@ -1472,15 +1473,15 @@ public: SourceLocation getOpLoc() const { return OpLoc; } void setOpLoc(SourceLocation L) { OpLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { - return getBase()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getBase()->getBeginLoc(); } SourceLocation getBaseLocEnd() const LLVM_READONLY { - return getBase()->getLocEnd(); + return getBase()->getEndLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return IsaMemberLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return IsaMemberLoc; } SourceLocation getExprLoc() const LLVM_READONLY { return IsaMemberLoc; } @@ -1549,10 +1550,12 @@ public: child_range children() { return child_range(&Operand, &Operand+1); } // Source locations are determined by the subexpression. - SourceLocation getLocStart() const LLVM_READONLY { - return Operand->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return Operand->getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY { + return Operand->getEndLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Operand->getLocEnd();} SourceLocation getExprLoc() const LLVM_READONLY { return getSubExpr()->getExprLoc(); @@ -1571,8 +1574,7 @@ public: /// \endcode class ObjCBridgedCastExpr final : public ExplicitCastExpr, - private llvm::TrailingObjects< - ObjCBridgedCastExpr, CastExpr::BasePathSizeTy, CXXBaseSpecifier *> { + private llvm::TrailingObjects<ObjCBridgedCastExpr, CXXBaseSpecifier *> { friend class ASTStmtReader; friend class ASTStmtWriter; friend class CastExpr; @@ -1582,10 +1584,6 @@ class ObjCBridgedCastExpr final SourceLocation BridgeKeywordLoc; unsigned Kind : 2; - size_t numTrailingObjects(OverloadToken<CastExpr::BasePathSizeTy>) const { - return path_empty() ? 0 : 1; - } - public: ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, CastKind CK, SourceLocation BridgeKeywordLoc, @@ -1611,10 +1609,10 @@ public: /// The location of the bridge keyword. SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; } - SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return getSubExpr()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getSubExpr()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -1651,8 +1649,8 @@ public: explicit ObjCAvailabilityCheckExpr(EmptyShell Shell) : Expr(ObjCAvailabilityCheckExprClass, Shell) {} - SourceLocation getLocStart() const { return AtLoc; } - SourceLocation getLocEnd() const { return RParen; } + SourceLocation getBeginLoc() const { return AtLoc; } + SourceLocation getEndLoc() const { return RParen; } SourceRange getSourceRange() const { return {AtLoc, RParen}; } /// This may be '*', in which case this should fold to true. diff --git a/include/clang/AST/ExprOpenMP.h b/include/clang/AST/ExprOpenMP.h index 2b4b5ec4d0e4..d88eebf5e54f 100644 --- a/include/clang/AST/ExprOpenMP.h +++ b/include/clang/AST/ExprOpenMP.h @@ -101,10 +101,10 @@ public: /// Set length of the array section. void setLength(Expr *E) { SubExprs[LENGTH] = E; } - SourceLocation getLocStart() const LLVM_READONLY { - return getBase()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getBase()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; } SourceLocation getColonLoc() const { return ColonLoc; } void setColonLoc(SourceLocation L) { ColonLoc = L; } diff --git a/include/clang/AST/FormatString.h b/include/clang/AST/FormatString.h new file mode 100644 index 000000000000..4a89c797b648 --- /dev/null +++ b/include/clang/AST/FormatString.h @@ -0,0 +1,752 @@ +//= FormatString.h - Analysis of printf/fprintf format strings --*- 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 APIs for analyzing the format strings of printf, fscanf, +// and friends. +// +// The structure of format strings for fprintf are described in C99 7.19.6.1. +// +// The structure of format strings for fscanf are described in C99 7.19.6.2. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H + +#include "clang/AST/CanonicalType.h" + +namespace clang { + +class TargetInfo; + +//===----------------------------------------------------------------------===// +/// Common components of both fprintf and fscanf format strings. +namespace analyze_format_string { + +/// Class representing optional flags with location and representation +/// information. +class OptionalFlag { +public: + OptionalFlag(const char *Representation) + : representation(Representation), flag(false) {} + bool isSet() const { return flag; } + void set() { flag = true; } + void clear() { flag = false; } + void setPosition(const char *position) { + assert(position); + flag = true; + this->position = position; + } + const char *getPosition() const { + assert(position); + return position; + } + const char *toString() const { return representation; } + + // Overloaded operators for bool like qualities + explicit operator bool() const { return flag; } + OptionalFlag& operator=(const bool &rhs) { + flag = rhs; + return *this; // Return a reference to myself. + } +private: + const char *representation; + const char *position; + bool flag; +}; + +/// Represents the length modifier in a format string in scanf/printf. +class LengthModifier { +public: + enum Kind { + None, + AsChar, // 'hh' + AsShort, // 'h' + AsLong, // 'l' + AsLongLong, // 'll' + AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) + AsIntMax, // 'j' + AsSizeT, // 'z' + AsPtrDiff, // 't' + AsInt32, // 'I32' (MSVCRT, like __int32) + AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL) + AsInt64, // 'I64' (MSVCRT, like __int64) + AsLongDouble, // 'L' + AsAllocate, // for '%as', GNU extension to C90 scanf + AsMAllocate, // for '%ms', GNU extension to scanf + AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z + AsWideChar = AsLong // for '%ls', only makes sense for printf + }; + + LengthModifier() + : Position(nullptr), kind(None) {} + LengthModifier(const char *pos, Kind k) + : Position(pos), kind(k) {} + + const char *getStart() const { + return Position; + } + + unsigned getLength() const { + switch (kind) { + default: + return 1; + case AsLongLong: + case AsChar: + return 2; + case AsInt32: + case AsInt64: + return 3; + case None: + return 0; + } + } + + Kind getKind() const { return kind; } + void setKind(Kind k) { kind = k; } + + const char *toString() const; + +private: + const char *Position; + Kind kind; +}; + +class ConversionSpecifier { +public: + enum Kind { + InvalidSpecifier = 0, + // C99 conversion specifiers. + cArg, + dArg, + DArg, // Apple extension + iArg, + IntArgBeg = dArg, + IntArgEnd = iArg, + + oArg, + OArg, // Apple extension + uArg, + UArg, // Apple extension + xArg, + XArg, + UIntArgBeg = oArg, + UIntArgEnd = XArg, + + fArg, + FArg, + eArg, + EArg, + gArg, + GArg, + aArg, + AArg, + DoubleArgBeg = fArg, + DoubleArgEnd = AArg, + + sArg, + pArg, + nArg, + PercentArg, + CArg, + SArg, + + // Apple extension: P specifies to os_log that the data being pointed to is + // to be copied by os_log. The precision indicates the number of bytes to + // copy. + PArg, + + // ** Printf-specific ** + + ZArg, // MS extension + + // Objective-C specific specifiers. + ObjCObjArg, // '@' + ObjCBeg = ObjCObjArg, + ObjCEnd = ObjCObjArg, + + // FreeBSD kernel specific specifiers. + FreeBSDbArg, + FreeBSDDArg, + FreeBSDrArg, + FreeBSDyArg, + + // GlibC specific specifiers. + PrintErrno, // 'm' + + PrintfConvBeg = ObjCObjArg, + PrintfConvEnd = PrintErrno, + + // ** Scanf-specific ** + ScanListArg, // '[' + ScanfConvBeg = ScanListArg, + ScanfConvEnd = ScanListArg + }; + + ConversionSpecifier(bool isPrintf = true) + : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr), + kind(InvalidSpecifier) {} + + ConversionSpecifier(bool isPrintf, const char *pos, Kind k) + : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {} + + const char *getStart() const { + return Position; + } + + StringRef getCharacters() const { + return StringRef(getStart(), getLength()); + } + + bool consumesDataArgument() const { + switch (kind) { + case PrintErrno: + assert(IsPrintf); + return false; + case PercentArg: + return false; + case InvalidSpecifier: + return false; + default: + return true; + } + } + + Kind getKind() const { return kind; } + void setKind(Kind k) { kind = k; } + unsigned getLength() const { + return EndScanList ? EndScanList - Position : 1; + } + void setEndScanList(const char *pos) { EndScanList = pos; } + + bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) || + kind == FreeBSDrArg || kind == FreeBSDyArg; } + bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } + bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; } + bool isDoubleArg() const { + return kind >= DoubleArgBeg && kind <= DoubleArgEnd; + } + + const char *toString() const; + + bool isPrintfKind() const { return IsPrintf; } + + Optional<ConversionSpecifier> getStandardSpecifier() const; + +protected: + bool IsPrintf; + const char *Position; + const char *EndScanList; + Kind kind; +}; + +class ArgType { +public: + enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, + AnyCharTy, CStrTy, WCStrTy, WIntTy }; + + enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic }; + +private: + const Kind K; + QualType T; + const char *Name = nullptr; + bool Ptr = false; + + /// The TypeKind identifies certain well-known types like size_t and + /// ptrdiff_t. + enum class TypeKind { DontCare, SizeT, PtrdiffT }; + TypeKind TK = TypeKind::DontCare; + +public: + ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {} + ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {} + ArgType(CanQualType T) : K(SpecificTy), T(T) {} + + static ArgType Invalid() { return ArgType(InvalidTy); } + bool isValid() const { return K != InvalidTy; } + + bool isSizeT() const { return TK == TypeKind::SizeT; } + + bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; } + + /// Create an ArgType which corresponds to the type pointer to A. + static ArgType PtrTo(const ArgType& A) { + assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); + ArgType Res = A; + Res.Ptr = true; + return Res; + } + + /// Create an ArgType which corresponds to the size_t/ssize_t type. + static ArgType makeSizeT(const ArgType &A) { + ArgType Res = A; + Res.TK = TypeKind::SizeT; + return Res; + } + + /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t + /// type. + static ArgType makePtrdiffT(const ArgType &A) { + ArgType Res = A; + Res.TK = TypeKind::PtrdiffT; + return Res; + } + + MatchKind matchesType(ASTContext &C, QualType argTy) const; + + QualType getRepresentativeType(ASTContext &C) const; + + ArgType makeVectorType(ASTContext &C, unsigned NumElts) const; + + std::string getRepresentativeTypeName(ASTContext &C) const; +}; + +class OptionalAmount { +public: + enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; + + OptionalAmount(HowSpecified howSpecified, + unsigned amount, + const char *amountStart, + unsigned amountLength, + bool usesPositionalArg) + : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), + UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {} + + OptionalAmount(bool valid = true) + : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0), + UsesPositionalArg(0), UsesDotPrefix(0) {} + + explicit OptionalAmount(unsigned Amount) + : start(nullptr), length(0), hs(Constant), amt(Amount), + UsesPositionalArg(false), UsesDotPrefix(false) {} + + bool isInvalid() const { + return hs == Invalid; + } + + HowSpecified getHowSpecified() const { return hs; } + void setHowSpecified(HowSpecified h) { hs = h; } + + bool hasDataArgument() const { return hs == Arg; } + + unsigned getArgIndex() const { + assert(hasDataArgument()); + return amt; + } + + unsigned getConstantAmount() const { + assert(hs == Constant); + return amt; + } + + const char *getStart() const { + // We include the . character if it is given. + return start - UsesDotPrefix; + } + + unsigned getConstantLength() const { + assert(hs == Constant); + return length + UsesDotPrefix; + } + + ArgType getArgType(ASTContext &Ctx) const; + + void toString(raw_ostream &os) const; + + bool usesPositionalArg() const { return (bool) UsesPositionalArg; } + unsigned getPositionalArgIndex() const { + assert(hasDataArgument()); + return amt + 1; + } + + bool usesDotPrefix() const { return UsesDotPrefix; } + void setUsesDotPrefix() { UsesDotPrefix = true; } + +private: + const char *start; + unsigned length; + HowSpecified hs; + unsigned amt; + bool UsesPositionalArg : 1; + bool UsesDotPrefix; +}; + + +class FormatSpecifier { +protected: + LengthModifier LM; + OptionalAmount FieldWidth; + ConversionSpecifier CS; + OptionalAmount VectorNumElts; + + /// Positional arguments, an IEEE extension: + /// IEEE Std 1003.1, 2004 Edition + /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html + bool UsesPositionalArg; + unsigned argIndex; +public: + FormatSpecifier(bool isPrintf) + : CS(isPrintf), VectorNumElts(false), + UsesPositionalArg(false), argIndex(0) {} + + void setLengthModifier(LengthModifier lm) { + LM = lm; + } + + void setUsesPositionalArg() { UsesPositionalArg = true; } + + void setArgIndex(unsigned i) { + argIndex = i; + } + + unsigned getArgIndex() const { + return argIndex; + } + + unsigned getPositionalArgIndex() const { + return argIndex + 1; + } + + const LengthModifier &getLengthModifier() const { + return LM; + } + + const OptionalAmount &getFieldWidth() const { + return FieldWidth; + } + + void setVectorNumElts(const OptionalAmount &Amt) { + VectorNumElts = Amt; + } + + const OptionalAmount &getVectorNumElts() const { + return VectorNumElts; + } + + void setFieldWidth(const OptionalAmount &Amt) { + FieldWidth = Amt; + } + + bool usesPositionalArg() const { return UsesPositionalArg; } + + bool hasValidLengthModifier(const TargetInfo &Target) const; + + bool hasStandardLengthModifier() const; + + Optional<LengthModifier> getCorrectedLengthModifier() const; + + bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; + + bool hasStandardLengthConversionCombination() const; + + /// For a TypedefType QT, if it is a named integer type such as size_t, + /// assign the appropriate value to LM and return true. + static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM); +}; + +} // end analyze_format_string namespace + +//===----------------------------------------------------------------------===// +/// Pieces specific to fprintf format strings. + +namespace analyze_printf { + +class PrintfConversionSpecifier : + public analyze_format_string::ConversionSpecifier { +public: + PrintfConversionSpecifier() + : ConversionSpecifier(true, nullptr, InvalidSpecifier) {} + + PrintfConversionSpecifier(const char *pos, Kind k) + : ConversionSpecifier(true, pos, k) {} + + bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } + bool isDoubleArg() const { return kind >= DoubleArgBeg && + kind <= DoubleArgEnd; } + + static bool classof(const analyze_format_string::ConversionSpecifier *CS) { + return CS->isPrintfKind(); + } +}; + +using analyze_format_string::ArgType; +using analyze_format_string::LengthModifier; +using analyze_format_string::OptionalAmount; +using analyze_format_string::OptionalFlag; + +class PrintfSpecifier : public analyze_format_string::FormatSpecifier { + OptionalFlag HasThousandsGrouping; // ''', POSIX extension. + OptionalFlag IsLeftJustified; // '-' + OptionalFlag HasPlusPrefix; // '+' + OptionalFlag HasSpacePrefix; // ' ' + OptionalFlag HasAlternativeForm; // '#' + OptionalFlag HasLeadingZeroes; // '0' + OptionalFlag HasObjCTechnicalTerm; // '[tt]' + OptionalFlag IsPrivate; // '{private}' + OptionalFlag IsPublic; // '{public}' + OptionalFlag IsSensitive; // '{sensitive}' + OptionalAmount Precision; + StringRef MaskType; + + ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const; + +public: + PrintfSpecifier() + : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"), + IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "), + HasAlternativeForm("#"), HasLeadingZeroes("0"), + HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"), + IsSensitive("sensitive") {} + + static PrintfSpecifier Parse(const char *beg, const char *end); + + // Methods for incrementally constructing the PrintfSpecifier. + void setConversionSpecifier(const PrintfConversionSpecifier &cs) { + CS = cs; + } + void setHasThousandsGrouping(const char *position) { + HasThousandsGrouping.setPosition(position); + } + void setIsLeftJustified(const char *position) { + IsLeftJustified.setPosition(position); + } + void setHasPlusPrefix(const char *position) { + HasPlusPrefix.setPosition(position); + } + void setHasSpacePrefix(const char *position) { + HasSpacePrefix.setPosition(position); + } + void setHasAlternativeForm(const char *position) { + HasAlternativeForm.setPosition(position); + } + void setHasLeadingZeros(const char *position) { + HasLeadingZeroes.setPosition(position); + } + void setHasObjCTechnicalTerm(const char *position) { + HasObjCTechnicalTerm.setPosition(position); + } + void setIsPrivate(const char *position) { IsPrivate.setPosition(position); } + void setIsPublic(const char *position) { IsPublic.setPosition(position); } + void setIsSensitive(const char *position) { + IsSensitive.setPosition(position); + } + void setUsesPositionalArg() { UsesPositionalArg = true; } + + // Methods for querying the format specifier. + + const PrintfConversionSpecifier &getConversionSpecifier() const { + return cast<PrintfConversionSpecifier>(CS); + } + + void setPrecision(const OptionalAmount &Amt) { + Precision = Amt; + Precision.setUsesDotPrefix(); + } + + const OptionalAmount &getPrecision() const { + return Precision; + } + + bool consumesDataArgument() const { + return getConversionSpecifier().consumesDataArgument(); + } + + /// Returns the builtin type that a data argument + /// paired with this format specifier should have. This method + /// will return null if the format specifier does not have + /// a matching data argument or the matching argument matches + /// more than one type. + ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; + + const OptionalFlag &hasThousandsGrouping() const { + return HasThousandsGrouping; + } + const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } + const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } + const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } + const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } + const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } + const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; } + const OptionalFlag &isPrivate() const { return IsPrivate; } + const OptionalFlag &isPublic() const { return IsPublic; } + const OptionalFlag &isSensitive() const { return IsSensitive; } + bool usesPositionalArg() const { return UsesPositionalArg; } + + StringRef getMaskType() const { return MaskType; } + void setMaskType(StringRef S) { MaskType = S; } + + /// Changes the specifier and length according to a QualType, retaining any + /// flags or options. Returns true on success, or false when a conversion + /// was not successful. + bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, + bool IsObjCLiteral); + + void toString(raw_ostream &os) const; + + // Validation methods - to check if any element results in undefined behavior + bool hasValidPlusPrefix() const; + bool hasValidAlternativeForm() const; + bool hasValidLeadingZeros() const; + bool hasValidSpacePrefix() const; + bool hasValidLeftJustified() const; + bool hasValidThousandsGroupingPrefix() const; + + bool hasValidPrecision() const; + bool hasValidFieldWidth() const; +}; +} // end analyze_printf namespace + +//===----------------------------------------------------------------------===// +/// Pieces specific to fscanf format strings. + +namespace analyze_scanf { + +class ScanfConversionSpecifier : + public analyze_format_string::ConversionSpecifier { +public: + ScanfConversionSpecifier() + : ConversionSpecifier(false, nullptr, InvalidSpecifier) {} + + ScanfConversionSpecifier(const char *pos, Kind k) + : ConversionSpecifier(false, pos, k) {} + + static bool classof(const analyze_format_string::ConversionSpecifier *CS) { + return !CS->isPrintfKind(); + } +}; + +using analyze_format_string::ArgType; +using analyze_format_string::LengthModifier; +using analyze_format_string::OptionalAmount; +using analyze_format_string::OptionalFlag; + +class ScanfSpecifier : public analyze_format_string::FormatSpecifier { + OptionalFlag SuppressAssignment; // '*' +public: + ScanfSpecifier() : + FormatSpecifier(/* isPrintf = */ false), + SuppressAssignment("*") {} + + void setSuppressAssignment(const char *position) { + SuppressAssignment.setPosition(position); + } + + const OptionalFlag &getSuppressAssignment() const { + return SuppressAssignment; + } + + void setConversionSpecifier(const ScanfConversionSpecifier &cs) { + CS = cs; + } + + const ScanfConversionSpecifier &getConversionSpecifier() const { + return cast<ScanfConversionSpecifier>(CS); + } + + bool consumesDataArgument() const { + return CS.consumesDataArgument() && !SuppressAssignment; + } + + ArgType getArgType(ASTContext &Ctx) const; + + bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt, + ASTContext &Ctx); + + void toString(raw_ostream &os) const; + + static ScanfSpecifier Parse(const char *beg, const char *end); +}; + +} // end analyze_scanf namespace + +//===----------------------------------------------------------------------===// +// Parsing and processing of format strings (both fprintf and fscanf). + +namespace analyze_format_string { + +enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; + +class FormatStringHandler { +public: + FormatStringHandler() {} + virtual ~FormatStringHandler(); + + virtual void HandleNullChar(const char *nullCharacter) {} + + virtual void HandlePosition(const char *startPos, unsigned posLen) {} + + virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, + PositionContext p) {} + + virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} + + virtual void HandleIncompleteSpecifier(const char *startSpecifier, + unsigned specifierLen) {} + + virtual void HandleEmptyObjCModifierFlag(const char *startFlags, + unsigned flagsLen) {} + + virtual void HandleInvalidObjCModifierFlag(const char *startFlag, + unsigned flagLen) {} + + virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, + const char *flagsEnd, + const char *conversionPosition) {} + // Printf-specific handlers. + + virtual bool HandleInvalidPrintfConversionSpecifier( + const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + /// Handle mask types whose sizes are not between one and eight bytes. + virtual void handleInvalidMaskType(StringRef MaskType) {} + + // Scanf-specific handlers. + + virtual bool HandleInvalidScanfConversionSpecifier( + const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + virtual void HandleIncompleteScanList(const char *start, const char *end) {} +}; + +bool ParsePrintfString(FormatStringHandler &H, + const char *beg, const char *end, const LangOptions &LO, + const TargetInfo &Target, bool isFreeBSDKPrintf); + +bool ParseFormatStringHasSArg(const char *beg, const char *end, + const LangOptions &LO, const TargetInfo &Target); + +bool ParseScanfString(FormatStringHandler &H, + const char *beg, const char *end, const LangOptions &LO, + const TargetInfo &Target); + +} // end analyze_format_string namespace +} // end clang namespace +#endif diff --git a/include/clang/AST/GlobalDecl.h b/include/clang/AST/GlobalDecl.h index 7f017994216f..a3c0cab3799f 100644 --- a/include/clang/AST/GlobalDecl.h +++ b/include/clang/AST/GlobalDecl.h @@ -34,6 +34,7 @@ namespace clang { /// a VarDecl, a FunctionDecl or a BlockDecl. class GlobalDecl { llvm::PointerIntPair<const Decl *, 2> Value; + unsigned MultiVersionIndex = 0; void Init(const Decl *D) { assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!"); @@ -45,7 +46,10 @@ class GlobalDecl { public: GlobalDecl() = default; GlobalDecl(const VarDecl *D) { Init(D);} - GlobalDecl(const FunctionDecl *D) { Init(D); } + GlobalDecl(const FunctionDecl *D, unsigned MVIndex = 0) + : MultiVersionIndex(MVIndex) { + Init(D); + } GlobalDecl(const BlockDecl *D) { Init(D); } GlobalDecl(const CapturedDecl *D) { Init(D); } GlobalDecl(const ObjCMethodDecl *D) { Init(D); } @@ -57,6 +61,7 @@ public: GlobalDecl CanonGD; CanonGD.Value.setPointer(Value.getPointer()->getCanonicalDecl()); CanonGD.Value.setInt(Value.getInt()); + CanonGD.MultiVersionIndex = MultiVersionIndex; return CanonGD; } @@ -73,8 +78,17 @@ public: return static_cast<CXXDtorType>(Value.getInt()); } + unsigned getMultiVersionIndex() const { + assert(isa<FunctionDecl>(getDecl()) && + !isa<CXXConstructorDecl>(getDecl()) && + !isa<CXXDestructorDecl>(getDecl()) && + "Decl is not a plain FunctionDecl!"); + return MultiVersionIndex; + } + friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) { - return LHS.Value == RHS.Value; + return LHS.Value == RHS.Value && + LHS.MultiVersionIndex == RHS.MultiVersionIndex; } void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } @@ -90,6 +104,16 @@ public: Result.Value.setPointer(D); return Result; } + + GlobalDecl getWithMultiVersionIndex(unsigned Index) { + assert(isa<FunctionDecl>(getDecl()) && + !isa<CXXConstructorDecl>(getDecl()) && + !isa<CXXDestructorDecl>(getDecl()) && + "Decl is not a plain FunctionDecl!"); + GlobalDecl Result(*this); + Result.MultiVersionIndex = Index; + return Result; + } }; } // namespace clang diff --git a/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h b/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h index 264f20f19ad5..47dac4362c8e 100644 --- a/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h +++ b/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h @@ -99,8 +99,8 @@ public: LexicallyNestedDeclarations.clear(); for (++I; I != E; ++I) { Decl *Sibling = *I; - if (!SM.isBeforeInTranslationUnit(Sibling->getLocStart(), - Child->getLocEnd())) + if (!SM.isBeforeInTranslationUnit(Sibling->getBeginLoc(), + Child->getEndLoc())) break; if (!BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Sibling)) LexicallyNestedDeclarations.push_back(Sibling); diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h index c42fe91b3246..309ed5a1a5d2 100644 --- a/include/clang/AST/Mangle.h +++ b/include/clang/AST/Mangle.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_MANGLE_H #define LLVM_CLANG_AST_MANGLE_H +#include "clang/AST/Decl.h" #include "clang/AST/Type.h" #include "clang/Basic/ABI.h" #include "llvm/ADT/DenseMap.h" diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h index bf2afe38cbca..f9340c64f3eb 100644 --- a/include/clang/AST/NSAPI.h +++ b/include/clang/AST/NSAPI.h @@ -166,6 +166,14 @@ public: return getOrInitSelector(StringRef("isEqual"), isEqualSel); } + Selector getNewSelector() const { + return getOrInitNullarySelector("new", NewSel); + } + + Selector getInitSelector() const { + return getOrInitNullarySelector("init", InitSel); + } + /// Enumerates the NSNumber methods used to generate literals. enum NSNumberLiteralMethodKind { NSNumberWithChar, @@ -229,6 +237,7 @@ private: bool isObjCEnumerator(const Expr *E, StringRef name, IdentifierInfo *&II) const; Selector getOrInitSelector(ArrayRef<StringRef> Ids, Selector &Sel) const; + Selector getOrInitNullarySelector(StringRef Id, Selector &Sel) const; ASTContext &Ctx; @@ -251,7 +260,7 @@ private: mutable Selector objectForKeyedSubscriptSel, objectAtIndexedSubscriptSel, setObjectForKeyedSubscriptSel,setObjectAtIndexedSubscriptSel, - isEqualSel; + isEqualSel, InitSel, NewSel; mutable IdentifierInfo *BOOLId, *NSIntegerId, *NSUIntegerId; mutable IdentifierInfo *NSASCIIStringEncodingId, *NSUTF8StringEncodingId; diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index 3a7b45767dac..8befe9ae4258 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -212,9 +212,12 @@ public: /// parameter pack (for C++11 variadic templates). bool containsUnexpandedParameterPack() const; - /// Print this nested name specifier to the given output - /// stream. - void print(raw_ostream &OS, const PrintingPolicy &Policy) const; + /// Print this nested name specifier to the given output stream. If + /// `ResolveTemplateArguments` is true, we'll print actual types, e.g. + /// `ns::SomeTemplate<int, MyClass>` instead of + /// `ns::SomeTemplate<Container::value_type, T>`. + void print(raw_ostream &OS, const PrintingPolicy &Policy, + bool ResolveTemplateArguments = false) const; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(Prefix.getOpaqueValue()); @@ -225,6 +228,8 @@ public: /// in debugging. void dump(const LangOptions &LO) const; void dump() const; + void dump(llvm::raw_ostream &OS) const; + void dump(llvm::raw_ostream &OS, const LangOptions &LO) const; }; /// A C++ nested-name-specifier augmented with source location diff --git a/include/clang/AST/ODRHash.h b/include/clang/AST/ODRHash.h index 75b361789211..feaa83844a1a 100644 --- a/include/clang/AST/ODRHash.h +++ b/include/clang/AST/ODRHash.h @@ -13,6 +13,9 @@ /// //===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_ODRHASH_H +#define LLVM_CLANG_AST_ODRHASH_H + #include "clang/AST/DeclarationName.h" #include "clang/AST/Type.h" #include "clang/AST/TemplateBase.h" @@ -80,7 +83,7 @@ public: void AddIdentifierInfo(const IdentifierInfo *II); void AddNestedNameSpecifier(const NestedNameSpecifier *NNS); void AddTemplateName(TemplateName Name); - void AddDeclarationName(DeclarationName Name); + void AddDeclarationName(DeclarationName Name, bool TreatAsDecl = false); void AddTemplateArgument(TemplateArgument TA); void AddTemplateParameterList(const TemplateParameterList *TPL); @@ -88,6 +91,11 @@ public: void AddBoolean(bool value); static bool isWhitelistedDecl(const Decl* D, const DeclContext *Parent); + +private: + void AddDeclarationNameImpl(DeclarationName Name); }; } // end namespace clang + +#endif diff --git a/include/clang/AST/OSLog.h b/include/clang/AST/OSLog.h new file mode 100644 index 000000000000..2b21855e7a6e --- /dev/null +++ b/include/clang/AST/OSLog.h @@ -0,0 +1,161 @@ +//= OSLog.h - Analysis of calls to os_log builtins --*- 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 APIs for determining the layout of the data buffer for +// os_log() and os_trace(). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" + +namespace clang { +namespace analyze_os_log { + +/// An OSLogBufferItem represents a single item in the data written by a call +/// to os_log() or os_trace(). +class OSLogBufferItem { +public: + enum Kind { + // The item is a scalar (int, float, raw pointer, etc.). No further copying + // is required. This is the only kind allowed by os_trace(). + ScalarKind = 0, + + // The item is a count, which describes the length of the following item to + // be copied. A count may only be followed by an item of kind StringKind, + // WideStringKind, or PointerKind. + CountKind, + + // The item is a pointer to a C string. If preceded by a count 'n', + // os_log() will copy at most 'n' bytes from the pointer. + StringKind, + + // The item is a pointer to a block of raw data. This item must be preceded + // by a count 'n'. os_log() will copy exactly 'n' bytes from the pointer. + PointerKind, + + // The item is a pointer to an Objective-C object. os_log() may retain the + // object for later processing. + ObjCObjKind, + + // The item is a pointer to wide-char string. + WideStringKind, + + // The item is corresponding to the '%m' format specifier, no value is + // populated in the buffer and the runtime is loading the errno value. + ErrnoKind, + + // The item is a mask type. + MaskKind + }; + + enum { + // The item is marked "private" in the format string. + IsPrivate = 0x1, + + // The item is marked "public" in the format string. + IsPublic = 0x2, + + // The item is marked "sensitive" in the format string. + IsSensitive = 0x4 | IsPrivate + }; + +private: + Kind TheKind = ScalarKind; + const Expr *TheExpr = nullptr; + CharUnits ConstValue; + CharUnits Size; // size of the data, not including the header bytes + unsigned Flags = 0; + StringRef MaskType; + +public: + OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags, + StringRef maskType = StringRef()) + : TheKind(kind), TheExpr(expr), Size(size), Flags(flags), + MaskType(maskType) { + assert(((Flags == 0) || (Flags == IsPrivate) || (Flags == IsPublic) || + (Flags == IsSensitive)) && + "unexpected privacy flag"); + } + + OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags) + : TheKind(CountKind), ConstValue(value), + Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {} + + unsigned char getDescriptorByte() const { + unsigned char result = Flags; + result |= ((unsigned)getKind()) << 4; + return result; + } + + unsigned char getSizeByte() const { return size().getQuantity(); } + + Kind getKind() const { return TheKind; } + bool getIsPrivate() const { return (Flags & IsPrivate) != 0; } + + const Expr *getExpr() const { return TheExpr; } + CharUnits getConstValue() const { return ConstValue; } + CharUnits size() const { return Size; } + + StringRef getMaskType() const { return MaskType; } +}; + +class OSLogBufferLayout { +public: + SmallVector<OSLogBufferItem, 4> Items; + + enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 }; + + CharUnits size() const { + CharUnits result; + result += CharUnits::fromQuantity(2); // summary byte, num-args byte + for (auto &item : Items) { + // descriptor byte, size byte + result += item.size() + CharUnits::fromQuantity(2); + } + return result; + } + + bool hasPrivateItems() const { + return llvm::any_of( + Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); }); + } + + bool hasNonScalarOrMask() const { + return llvm::any_of(Items, [](const OSLogBufferItem &Item) { + return Item.getKind() != OSLogBufferItem::ScalarKind || + !Item.getMaskType().empty(); + }); + } + + unsigned char getSummaryByte() const { + unsigned char result = 0; + if (hasPrivateItems()) + result |= HasPrivateItems; + if (hasNonScalarOrMask()) + result |= HasNonScalarItems; + return result; + } + + unsigned char getNumArgsByte() const { return Items.size(); } +}; + +// Given a call 'E' to one of the builtins __builtin_os_log_format() or +// __builtin_os_log_format_buffer_size(), compute the layout of the buffer that +// the call will write into and store it in 'layout'. Returns 'false' if there +// was some error encountered while computing the layout, and 'true' otherwise. +bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E, + OSLogBufferLayout &layout); + +} // namespace analyze_os_log +} // namespace clang +#endif diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h index a28609f8cdf9..bdcdf74b2630 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -64,10 +64,10 @@ protected: public: /// Returns the starting location of the clause. - SourceLocation getLocStart() const { return StartLoc; } + SourceLocation getBeginLoc() const { return StartLoc; } /// Returns the ending location of the clause. - SourceLocation getLocEnd() const { return EndLoc; } + SourceLocation getEndLoc() const { return EndLoc; } /// Sets the starting location of the clause. void setLocStart(SourceLocation Loc) { StartLoc = Loc; } @@ -734,6 +734,210 @@ public: } }; +/// This represents 'unified_address' clause in the '#pragma omp requires' +/// directive. +/// +/// \code +/// #pragma omp requires unified_address +/// \endcode +/// In this example directive '#pragma omp requires' has 'unified_address' +/// clause. +class OMPUnifiedAddressClause final : public OMPClause { +public: + friend class OMPClauseReader; + /// Build 'unified_address' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + OMPUnifiedAddressClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_unified_address, StartLoc, EndLoc) {} + + /// Build an empty clause. + OMPUnifiedAddressClause() + : OMPClause(OMPC_unified_address, SourceLocation(), SourceLocation()) {} + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_unified_address; + } +}; + +/// This represents 'unified_shared_memory' clause in the '#pragma omp requires' +/// directive. +/// +/// \code +/// #pragma omp requires unified_shared_memory +/// \endcode +/// In this example directive '#pragma omp requires' has 'unified_shared_memory' +/// clause. +class OMPUnifiedSharedMemoryClause final : public OMPClause { +public: + friend class OMPClauseReader; + /// Build 'unified_shared_memory' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + OMPUnifiedSharedMemoryClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_unified_shared_memory, StartLoc, EndLoc) {} + + /// Build an empty clause. + OMPUnifiedSharedMemoryClause() + : OMPClause(OMPC_unified_shared_memory, SourceLocation(), SourceLocation()) {} + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_unified_shared_memory; + } +}; + +/// This represents 'reverse_offload' clause in the '#pragma omp requires' +/// directive. +/// +/// \code +/// #pragma omp requires reverse_offload +/// \endcode +/// In this example directive '#pragma omp requires' has 'reverse_offload' +/// clause. +class OMPReverseOffloadClause final : public OMPClause { +public: + friend class OMPClauseReader; + /// Build 'reverse_offload' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + OMPReverseOffloadClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_reverse_offload, StartLoc, EndLoc) {} + + /// Build an empty clause. + OMPReverseOffloadClause() + : OMPClause(OMPC_reverse_offload, SourceLocation(), SourceLocation()) {} + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_reverse_offload; + } +}; + +/// This represents 'dynamic_allocators' clause in the '#pragma omp requires' +/// directive. +/// +/// \code +/// #pragma omp requires dynamic_allocators +/// \endcode +/// In this example directive '#pragma omp requires' has 'dynamic_allocators' +/// clause. +class OMPDynamicAllocatorsClause final : public OMPClause { +public: + friend class OMPClauseReader; + /// Build 'dynamic_allocators' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + OMPDynamicAllocatorsClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_dynamic_allocators, StartLoc, EndLoc) {} + + /// Build an empty clause. + OMPDynamicAllocatorsClause() + : OMPClause(OMPC_dynamic_allocators, SourceLocation(), SourceLocation()) { + } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_dynamic_allocators; + } +}; + +/// This represents 'atomic_default_mem_order' clause in the '#pragma omp +/// requires' directive. +/// +/// \code +/// #pragma omp requires atomic_default_mem_order(seq_cst) +/// \endcode +/// In this example directive '#pragma omp requires' has simple +/// atomic_default_mem_order' clause with kind 'seq_cst'. +class OMPAtomicDefaultMemOrderClause final : public OMPClause { + friend class OMPClauseReader; + + /// Location of '(' + SourceLocation LParenLoc; + + /// A kind of the 'atomic_default_mem_order' clause. + OpenMPAtomicDefaultMemOrderClauseKind Kind = + OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown; + + /// Start location of the kind in source code. + SourceLocation KindKwLoc; + + /// Set kind of the clause. + /// + /// \param K Kind of clause. + void setAtomicDefaultMemOrderKind(OpenMPAtomicDefaultMemOrderClauseKind K) { + Kind = K; + } + + /// Set clause kind location. + /// + /// \param KLoc Kind location. + void setAtomicDefaultMemOrderKindKwLoc(SourceLocation KLoc) { + KindKwLoc = KLoc; + } + +public: + /// Build 'atomic_default_mem_order' clause with argument \a A ('seq_cst', + /// 'acq_rel' or 'relaxed'). + /// + /// \param A Argument of the clause ('seq_cst', 'acq_rel' or 'relaxed'). + /// \param ALoc Starting location of the argument. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + OMPAtomicDefaultMemOrderClause(OpenMPAtomicDefaultMemOrderClauseKind A, + SourceLocation ALoc, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_atomic_default_mem_order, StartLoc, EndLoc), + LParenLoc(LParenLoc), Kind(A), KindKwLoc(ALoc) {} + + /// Build an empty clause. + OMPAtomicDefaultMemOrderClause() + : OMPClause(OMPC_atomic_default_mem_order, SourceLocation(), + SourceLocation()) {} + + /// Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + + /// Returns the locaiton of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// Returns kind of the clause. + OpenMPAtomicDefaultMemOrderClauseKind getAtomicDefaultMemOrderKind() const { + return Kind; + } + + /// Returns location of clause kind. + SourceLocation getAtomicDefaultMemOrderKindKwLoc() const { return KindKwLoc; } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_atomic_default_mem_order; + } +}; + /// This represents 'schedule' clause in the '#pragma omp ...' directive. /// /// \code @@ -922,8 +1126,11 @@ public: /// \endcode /// In this example directive '#pragma omp for' has 'ordered' clause with /// parameter 2. -class OMPOrderedClause : public OMPClause { +class OMPOrderedClause final + : public OMPClause, + private llvm::TrailingObjects<OMPOrderedClause, Expr *> { friend class OMPClauseReader; + friend TrailingObjects; /// Location of '('. SourceLocation LParenLoc; @@ -931,6 +1138,26 @@ class OMPOrderedClause : public OMPClause { /// Number of for-loops. Stmt *NumForLoops = nullptr; + /// Real number of loops. + unsigned NumberOfLoops = 0; + + /// Build 'ordered' clause. + /// + /// \param Num Expression, possibly associated with this clause. + /// \param NumLoops Number of loops, associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + OMPOrderedClause(Expr *Num, unsigned NumLoops, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OMPClause(OMPC_ordered, StartLoc, EndLoc), LParenLoc(LParenLoc), + NumForLoops(Num), NumberOfLoops(NumLoops) {} + + /// Build an empty clause. + explicit OMPOrderedClause(unsigned NumLoops) + : OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()), + NumberOfLoops(NumLoops) {} + /// Set the number of associated for-loops. void setNumForLoops(Expr *Num) { NumForLoops = Num; } @@ -938,17 +1165,17 @@ public: /// Build 'ordered' clause. /// /// \param Num Expression, possibly associated with this clause. + /// \param NumLoops Number of loops, associated with this clause. /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. - OMPOrderedClause(Expr *Num, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc) - : OMPClause(OMPC_ordered, StartLoc, EndLoc), LParenLoc(LParenLoc), - NumForLoops(Num) {} + static OMPOrderedClause *Create(const ASTContext &C, Expr *Num, + unsigned NumLoops, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// Build an empty clause. - explicit OMPOrderedClause() - : OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()) {} + static OMPOrderedClause* CreateEmpty(const ASTContext &C, unsigned NumLoops); /// Sets the location of '('. void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } @@ -959,6 +1186,17 @@ public: /// Return the number of associated for-loops. Expr *getNumForLoops() const { return cast_or_null<Expr>(NumForLoops); } + /// Set number of iterations for the specified loop. + void setLoopNumIterations(unsigned NumLoop, Expr *NumIterations); + /// Get number of iterations for all the loops. + ArrayRef<Expr *> getLoopNumIterations() const; + + /// Set loop counter for the specified loop. + void setLoopCounter(unsigned NumLoop, Expr *Counter); + /// Get loops counter for the specified loop. + Expr *getLoopCounter(unsigned NumLoop); + const Expr *getLoopCounter(unsigned NumLoop) const; + child_range children() { return child_range(&NumForLoops, &NumForLoops + 1); } static bool classof(const OMPClause *T) { @@ -3087,24 +3325,32 @@ class OMPDependClause final /// Colon location. SourceLocation ColonLoc; + /// Number of loops, associated with the depend clause. + unsigned NumLoops = 0; + /// Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. + /// \param NumLoops Number of loops that is associated with this depend + /// clause. OMPDependClause(SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, unsigned N) + SourceLocation EndLoc, unsigned N, unsigned NumLoops) : OMPVarListClause<OMPDependClause>(OMPC_depend, StartLoc, LParenLoc, - EndLoc, N) {} + EndLoc, N), NumLoops(NumLoops) {} /// Build an empty clause. /// /// \param N Number of variables. - explicit OMPDependClause(unsigned N) + /// \param NumLoops Number of loops that is associated with this depend + /// clause. + explicit OMPDependClause(unsigned N, unsigned NumLoops) : OMPVarListClause<OMPDependClause>(OMPC_depend, SourceLocation(), SourceLocation(), SourceLocation(), - N) {} + N), + NumLoops(NumLoops) {} /// Set dependency kind. void setDependencyKind(OpenMPDependClauseKind K) { DepKind = K; } @@ -3126,16 +3372,23 @@ public: /// \param DepLoc Location of the dependency type. /// \param ColonLoc Colon location. /// \param VL List of references to the variables. - static OMPDependClause * - Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, OpenMPDependClauseKind DepKind, - SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL); + /// \param NumLoops Number of loops that is associated with this depend + /// clause. + static OMPDependClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VL, unsigned NumLoops); /// Creates an empty clause with \a N variables. /// /// \param C AST context. /// \param N The number of variables. - static OMPDependClause *CreateEmpty(const ASTContext &C, unsigned N); + /// \param NumLoops Number of loops that is associated with this depend + /// clause. + static OMPDependClause *CreateEmpty(const ASTContext &C, unsigned N, + unsigned NumLoops); /// Get dependency type. OpenMPDependClauseKind getDependencyKind() const { return DepKind; } @@ -3146,15 +3399,16 @@ public: /// Get colon location. SourceLocation getColonLoc() const { return ColonLoc; } - /// Set the loop counter value for the depend clauses with 'sink|source' kind - /// of dependency. Required for codegen. - void setCounterValue(Expr *V); + /// Get number of loops associated with the clause. + unsigned getNumLoops() const { return NumLoops; } - /// Get the loop counter value. - Expr *getCounterValue(); + /// Set the loop data for the depend clauses with 'sink|source' kind of + /// dependency. + void setLoopData(unsigned NumLoop, Expr *Cnt); - /// Get the loop counter value. - const Expr *getCounterValue() const; + /// Get the loop data. + Expr *getLoopData(unsigned NumLoop); + const Expr *getLoopData(unsigned NumLoop) const; child_range children() { return child_range(reinterpret_cast<Stmt **>(varlist_begin()), @@ -3807,8 +4061,19 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>, return getUniqueDeclarationsNum() + getTotalComponentListNum(); } - /// Map type modifier for the 'map' clause. - OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown; +public: + /// Number of allowed map-type-modifiers. + static constexpr unsigned NumberOfModifiers = + OMPC_MAP_MODIFIER_last - OMPC_MAP_MODIFIER_unknown - 1; + +private: + /// Map-type-modifiers for the 'map' clause. + OpenMPMapModifierKind MapTypeModifiers[NumberOfModifiers] = { + OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown + }; + + /// Location of map-type-modifiers for the 'map' clause. + SourceLocation MapTypeModifiersLoc[NumberOfModifiers]; /// Map type for the 'map' clause. OpenMPMapClauseKind MapType = OMPC_MAP_unknown; @@ -3826,7 +4091,8 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>, /// NumUniqueDeclarations declarations, \a NumComponentLists total component /// lists, and \a NumComponents total expression components. /// - /// \param MapTypeModifier Map type modifier. + /// \param MapModifiers Map-type-modifiers. + /// \param MapModifiersLoc Locations of map-type-modifiers. /// \param MapType Map type. /// \param MapTypeIsImplicit Map type is inferred implicitly. /// \param MapLoc Location of the map type. @@ -3837,7 +4103,8 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>, /// clause. /// \param NumComponentLists Number of component lists in this clause. /// \param NumComponents Total number of expression components in the clause. - explicit OMPMapClause(OpenMPMapClauseKind MapTypeModifier, + explicit OMPMapClause(ArrayRef<OpenMPMapModifierKind> MapModifiers, + ArrayRef<SourceLocation> MapModifiersLoc, OpenMPMapClauseKind MapType, bool MapTypeIsImplicit, SourceLocation MapLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, @@ -3846,8 +4113,17 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>, : OMPMappableExprListClause(OMPC_map, StartLoc, LParenLoc, EndLoc, NumVars, NumUniqueDeclarations, NumComponentLists, NumComponents), - MapTypeModifier(MapTypeModifier), MapType(MapType), - MapTypeIsImplicit(MapTypeIsImplicit), MapLoc(MapLoc) {} + MapType(MapType), MapTypeIsImplicit(MapTypeIsImplicit), + MapLoc(MapLoc) { + assert(llvm::array_lengthof(MapTypeModifiers) == MapModifiers.size() + && "Unexpected number of map type modifiers."); + llvm::copy(MapModifiers, std::begin(MapTypeModifiers)); + + assert(llvm::array_lengthof(MapTypeModifiersLoc) == + MapModifiersLoc.size() && + "Unexpected number of map type modifier locations."); + llvm::copy(MapModifiersLoc, std::begin(MapTypeModifiersLoc)); + } /// Build an empty clause. /// @@ -3862,10 +4138,25 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>, OMPC_map, SourceLocation(), SourceLocation(), SourceLocation(), NumVars, NumUniqueDeclarations, NumComponentLists, NumComponents) {} - /// Set type modifier for the clause. + /// Set map-type-modifier for the clause. /// - /// \param T Type Modifier for the clause. - void setMapTypeModifier(OpenMPMapClauseKind T) { MapTypeModifier = T; } + /// \param I index for map-type-modifier. + /// \param T map-type-modifier for the clause. + void setMapTypeModifier(unsigned I, OpenMPMapModifierKind T) { + assert(I < NumberOfModifiers && + "Unexpected index to store map type modifier, exceeds array size."); + MapTypeModifiers[I] = T; + } + + /// Set location for the map-type-modifier. + /// + /// \param I index for map-type-modifier location. + /// \param TLoc map-type-modifier location. + void setMapTypeModifierLoc(unsigned I, SourceLocation TLoc) { + assert(I < NumberOfModifiers && + "Index to store map type modifier location exceeds array size."); + MapTypeModifiersLoc[I] = TLoc; + } /// Set type for the clause. /// @@ -3889,7 +4180,8 @@ public: /// \param Vars The original expression used in the clause. /// \param Declarations Declarations used in the clause. /// \param ComponentLists Component lists used in the clause. - /// \param TypeModifier Map type modifier. + /// \param MapModifiers Map-type-modifiers. + /// \param MapModifiersLoc Location of map-type-modifiers. /// \param Type Map type. /// \param TypeIsImplicit Map type is inferred implicitly. /// \param TypeLoc Location of the map type. @@ -3898,7 +4190,8 @@ public: ArrayRef<Expr *> Vars, ArrayRef<ValueDecl *> Declarations, MappableExprComponentListsRef ComponentLists, - OpenMPMapClauseKind TypeModifier, + ArrayRef<OpenMPMapModifierKind> MapModifiers, + ArrayRef<SourceLocation> MapModifiersLoc, OpenMPMapClauseKind Type, bool TypeIsImplicit, SourceLocation TypeLoc); @@ -3928,9 +4221,33 @@ public: /// messages for some target directives. bool isImplicitMapType() const LLVM_READONLY { return MapTypeIsImplicit; } - /// Fetches the map type modifier for the clause. - OpenMPMapClauseKind getMapTypeModifier() const LLVM_READONLY { - return MapTypeModifier; + /// Fetches the map-type-modifier at 'Cnt' index of array of modifiers. + /// + /// \param Cnt index for map-type-modifier. + OpenMPMapModifierKind getMapTypeModifier(unsigned Cnt) const LLVM_READONLY { + assert(Cnt < NumberOfModifiers && + "Requested modifier exceeds the total number of modifiers."); + return MapTypeModifiers[Cnt]; + } + + /// Fetches the map-type-modifier location at 'Cnt' index of array of + /// modifiers' locations. + /// + /// \param Cnt index for map-type-modifier location. + SourceLocation getMapTypeModifierLoc(unsigned Cnt) const LLVM_READONLY { + assert(Cnt < NumberOfModifiers && + "Requested modifier location exceeds total number of modifiers."); + return MapTypeModifiersLoc[Cnt]; + } + + /// Fetches ArrayRef of map-type-modifiers. + ArrayRef<OpenMPMapModifierKind> getMapTypeModifiers() const LLVM_READONLY { + return llvm::makeArrayRef(MapTypeModifiers); + } + + /// Fetches ArrayRef of location of map-type-modifiers. + ArrayRef<SourceLocation> getMapTypeModifiersLoc() const LLVM_READONLY { + return llvm::makeArrayRef(MapTypeModifiersLoc); } /// Fetches location of clause mapping kind. @@ -4991,6 +5308,59 @@ public: } }; +/// This class implements a simple visitor for OMPClause +/// subclasses. +template<class ImplClass, template <typename> class Ptr, typename RetTy> +class OMPClauseVisitorBase { +public: +#define PTR(CLASS) typename Ptr<CLASS>::type +#define DISPATCH(CLASS) \ + return static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<PTR(CLASS)>(S)) + +#define OPENMP_CLAUSE(Name, Class) \ + RetTy Visit ## Class (PTR(Class) S) { DISPATCH(Class); } +#include "clang/Basic/OpenMPKinds.def" + + RetTy Visit(PTR(OMPClause) S) { + // Top switch clause: visit each OMPClause. + switch (S->getClauseKind()) { + default: llvm_unreachable("Unknown clause kind!"); +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_ ## Name : return Visit ## Class(static_cast<PTR(Class)>(S)); +#include "clang/Basic/OpenMPKinds.def" + } + } + // Base case, ignore it. :) + RetTy VisitOMPClause(PTR(OMPClause) Node) { return RetTy(); } +#undef PTR +#undef DISPATCH +}; + +template <typename T> +using const_ptr = typename std::add_pointer<typename std::add_const<T>::type>; + +template<class ImplClass, typename RetTy = void> +class OMPClauseVisitor : + public OMPClauseVisitorBase <ImplClass, std::add_pointer, RetTy> {}; +template<class ImplClass, typename RetTy = void> +class ConstOMPClauseVisitor : + public OMPClauseVisitorBase <ImplClass, const_ptr, RetTy> {}; + +class OMPClausePrinter final : public OMPClauseVisitor<OMPClausePrinter> { + raw_ostream &OS; + const PrintingPolicy &Policy; + + /// Process clauses with list of variables. + template <typename T> void VisitOMPClauseList(T *Node, char StartSym); + +public: + OMPClausePrinter(raw_ostream &OS, const PrintingPolicy &Policy) + : OS(OS), Policy(Policy) {} + +#define OPENMP_CLAUSE(Name, Class) void Visit##Class(Class *S); +#include "clang/Basic/OpenMPKinds.def" +}; + } // namespace clang #endif // LLVM_CLANG_AST_OPENMPCLAUSE_H diff --git a/include/clang/AST/OperationKinds.def b/include/clang/AST/OperationKinds.def index e2d65d84880c..cd19091e31d6 100644 --- a/include/clang/AST/OperationKinds.def +++ b/include/clang/AST/OperationKinds.def @@ -197,6 +197,14 @@ CAST_OPERATION(IntegralToBoolean) /// float f = i; CAST_OPERATION(IntegralToFloating) +/// CK_FixedPointCast - Fixed point to fixed point. +/// (_Accum) 0.5r +CAST_OPERATION(FixedPointCast) + +/// CK_FixedPointToBoolean - Fixed point to boolean. +/// (bool) 0.5r +CAST_OPERATION(FixedPointToBoolean) + /// CK_FloatingToIntegral - Floating point to integral. Rounds /// towards zero, discarding any fractional component. /// (int) f @@ -318,11 +326,9 @@ CAST_OPERATION(CopyAndAutoreleaseBlockObject) // callee of a call expression. CAST_OPERATION(BuiltinFnToFnPtr) -// Convert a zero value for OpenCL event_t initialization. -CAST_OPERATION(ZeroToOCLEvent) - -// Convert a zero value for OpenCL queue_t initialization. -CAST_OPERATION(ZeroToOCLQueue) +// Convert a zero value for OpenCL opaque types initialization (event_t, +// queue_t, etc.) +CAST_OPERATION(ZeroToOCLOpaqueType) // Convert a pointer to a different address space. CAST_OPERATION(AddressSpaceConversion) diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index b49f5be1b1e6..3c877f5ea19c 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -38,21 +38,20 @@ public: struct PrintingPolicy { /// Create a default printing policy for the specified language. PrintingPolicy(const LangOptions &LO) - : Indentation(2), SuppressSpecifiers(false), - SuppressTagKeyword(LO.CPlusPlus), - IncludeTagDefinition(false), SuppressScope(false), - SuppressUnwrittenScope(false), SuppressInitializers(false), - ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), - SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), - SuppressTemplateArgsInCXXConstructors(false), - Bool(LO.Bool), Restrict(LO.C99), - Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11), - UseVoidForZeroParams(!LO.CPlusPlus), - TerseOutput(false), PolishForDeclaration(false), - Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), - IncludeNewlines(true), MSVCFormatting(false), - ConstantsAsWritten(false), SuppressImplicitBase(false), - FullyQualifiedName(false) { } + : Indentation(2), SuppressSpecifiers(false), + SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false), + SuppressScope(false), SuppressUnwrittenScope(false), + SuppressInitializers(false), ConstantArraySizeAsWritten(false), + AnonymousTagLocations(true), SuppressStrongLifetime(false), + SuppressLifetimeQualifiers(false), + SuppressTemplateArgsInCXXConstructors(false), Bool(LO.Bool), + Restrict(LO.C99), Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11), + UseVoidForZeroParams(!LO.CPlusPlus), TerseOutput(false), + PolishForDeclaration(false), Half(LO.Half), + MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), + MSVCFormatting(false), ConstantsAsWritten(false), + SuppressImplicitBase(false), FullyQualifiedName(false), + RemapFilePaths(false), PrintCanonicalTypes(false) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -81,7 +80,7 @@ struct PrintingPolicy { /// declaration for "x", so that we will print "int *x"; it will be /// \c true when we print "y", so that we suppress printing the /// "const int" type specifier and instead only print the "*y". - bool SuppressSpecifiers : 1; + unsigned SuppressSpecifiers : 1; /// Whether type printing should skip printing the tag keyword. /// @@ -91,7 +90,7 @@ struct PrintingPolicy { /// \code /// struct Geometry::Point; /// \endcode - bool SuppressTagKeyword : 1; + unsigned SuppressTagKeyword : 1; /// When true, include the body of a tag definition. /// @@ -101,14 +100,14 @@ struct PrintingPolicy { /// \code /// typedef struct { int x, y; } Point; /// \endcode - bool IncludeTagDefinition : 1; + unsigned IncludeTagDefinition : 1; /// Suppresses printing of scope specifiers. - bool SuppressScope : 1; + unsigned SuppressScope : 1; /// Suppress printing parts of scope specifiers that don't need /// to be written, e.g., for inline or anonymous namespaces. - bool SuppressUnwrittenScope : 1; + unsigned SuppressUnwrittenScope : 1; /// Suppress printing of variable initializers. /// @@ -121,7 +120,7 @@ struct PrintingPolicy { /// /// SuppressInitializers will be true when printing "auto x", so that the /// internal initializer constructed for x will not be printed. - bool SuppressInitializers : 1; + unsigned SuppressInitializers : 1; /// Whether we should print the sizes of constant array expressions as written /// in the sources. @@ -139,12 +138,12 @@ struct PrintingPolicy { /// int a[104]; /// char a[9] = "A string"; /// \endcode - bool ConstantArraySizeAsWritten : 1; + unsigned ConstantArraySizeAsWritten : 1; /// When printing an anonymous tag name, also print the location of that /// entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just prints /// "(anonymous)" for the name. - bool AnonymousTagLocations : 1; + unsigned AnonymousTagLocations : 1; /// When true, suppress printing of the __strong lifetime qualifier in ARC. unsigned SuppressStrongLifetime : 1; @@ -199,7 +198,7 @@ struct PrintingPolicy { /// Use whitespace and punctuation like MSVC does. In particular, this prints /// anonymous namespaces as `anonymous namespace' and does not insert spaces /// after template arguments. - bool MSVCFormatting : 1; + unsigned MSVCFormatting : 1; /// Whether we should print the constant expressions as written in the /// sources. @@ -217,14 +216,23 @@ struct PrintingPolicy { /// 0x10 /// 2.5e3 /// \endcode - bool ConstantsAsWritten : 1; + unsigned ConstantsAsWritten : 1; /// When true, don't print the implicit 'self' or 'this' expressions. - bool SuppressImplicitBase : 1; + unsigned SuppressImplicitBase : 1; /// When true, print the fully qualified name of function declarations. /// This is the opposite of SuppressScope and thus overrules it. - bool FullyQualifiedName : 1; + unsigned FullyQualifiedName : 1; + + /// Whether to apply -fdebug-prefix-map to any file paths. + unsigned RemapFilePaths : 1; + + /// Whether to print types as written or canonically. + unsigned PrintCanonicalTypes : 1; + + /// When RemapFilePaths is true, this function performs the action. + std::function<std::string(StringRef)> remapPath; }; } // end namespace clang diff --git a/include/clang/AST/RawCommentList.h b/include/clang/AST/RawCommentList.h index 8327efc750fd..d17c9df67e41 100644 --- a/include/clang/AST/RawCommentList.h +++ b/include/clang/AST/RawCommentList.h @@ -101,8 +101,8 @@ public: } SourceRange getSourceRange() const LLVM_READONLY { return Range; } - SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } - SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } const char *getBriefText(const ASTContext &Context) const { if (BriefTextValid) @@ -180,7 +180,7 @@ public: explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { } bool operator()(const RawComment &LHS, const RawComment &RHS) { - return SM.isBeforeInTranslationUnit(LHS.getLocStart(), RHS.getLocStart()); + return SM.isBeforeInTranslationUnit(LHS.getBeginLoc(), RHS.getBeginLoc()); } bool operator()(const RawComment *LHS, const RawComment *RHS) { diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 0d2b670507c1..44aba6355758 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -176,6 +176,16 @@ public: /// Return whether this visitor should traverse post-order. bool shouldTraversePostOrder() const { return false; } + /// Recursively visits an entire AST, starting from the top-level Decls + /// in the AST traversal scope (by default, the TranslationUnitDecl). + /// \returns false if visitation was terminated early. + bool TraverseAST(ASTContext &AST) { + for (Decl *D : AST.getTraversalScope()) + if (!getDerived().TraverseDecl(D)) + return false; + return true; + } + /// Recursively visit a statement or expression, by /// dispatching to Traverse*() based on the argument's dynamic type. /// @@ -288,14 +298,6 @@ public: bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init); - /// Recursively visit the body of a lambda expression. - /// - /// This provides a hook for visitors that need more context when visiting - /// \c LE->getBody(). - /// - /// \returns false if the visitation was terminated early, true otherwise. - bool TraverseLambdaBody(LambdaExpr *LE, DataRecursionQueue *Queue = nullptr); - /// Recursively visit the syntactic or semantic form of an /// initialization list. /// @@ -926,13 +928,6 @@ RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE, return true; } -template <typename Derived> -bool RecursiveASTVisitor<Derived>::TraverseLambdaBody( - LambdaExpr *LE, DataRecursionQueue *Queue) { - TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(LE->getBody()); - return true; -} - // ----------------- Type traversal ----------------- // This macro makes available a variable T, the passed-in type. @@ -1373,9 +1368,14 @@ DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) template <typename Derived> bool RecursiveASTVisitor<Derived>::canIgnoreChildDeclWhileTraversingDeclContext( const Decl *Child) { - // BlockDecls and CapturedDecls are traversed through BlockExprs and - // CapturedStmts respectively. - return isa<BlockDecl>(Child) || isa<CapturedDecl>(Child); + // BlockDecls are traversed through BlockExprs, + // CapturedDecls are traversed through CapturedStmts. + if (isa<BlockDecl>(Child) || isa<CapturedDecl>(Child)) + return true; + // Lambda classes are traversed through LambdaExprs. + if (const CXXRecordDecl* Cls = dyn_cast<CXXRecordDecl>(Child)) + return Cls->isLambda(); + return false; } template <typename Derived> @@ -1589,6 +1589,12 @@ DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, { for (auto *I : D->varlists()) { TRY_TO(TraverseStmt(I)); } + }) + +DEF_TRAVERSE_DECL(OMPRequiresDecl, { + for (auto *C : D->clauselists()) { + TRY_TO(TraverseOMPClause(C)); + } }) DEF_TRAVERSE_DECL(OMPDeclareReductionDecl, { @@ -2174,6 +2180,8 @@ DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, {}) DEF_TRAVERSE_STMT(CXXForRangeStmt, { if (!getDerived().shouldVisitImplicitCode()) { + if (S->getInit()) + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getInit()); TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLoopVarStmt()); TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRangeInit()); TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody()); @@ -2191,6 +2199,8 @@ DEF_TRAVERSE_STMT(ReturnStmt, {}) DEF_TRAVERSE_STMT(SwitchStmt, {}) DEF_TRAVERSE_STMT(WhileStmt, {}) +DEF_TRAVERSE_STMT(ConstantExpr, {}) + DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo())); @@ -2384,6 +2394,7 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, { // Walk only the visible parts of lambda expressions. DEF_TRAVERSE_STMT(LambdaExpr, { + // Visit the capture list. for (unsigned I = 0, N = S->capture_size(); I != N; ++I) { const LambdaCapture *C = S->capture_begin() + I; if (C->isExplicit() || getDerived().shouldVisitImplicitCode()) { @@ -2391,32 +2402,31 @@ DEF_TRAVERSE_STMT(LambdaExpr, { } } - TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>(); - - if (S->hasExplicitParameters() && S->hasExplicitResultType()) { - // Visit the whole type. - TRY_TO(TraverseTypeLoc(TL)); + if (getDerived().shouldVisitImplicitCode()) { + // The implicit model is simple: everything else is in the lambda class. + TRY_TO(TraverseDecl(S->getLambdaClass())); } else { + // We need to poke around to find the bits that might be explicitly written. + TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>(); + if (S->hasExplicitParameters()) { // Visit parameters. - for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) TRY_TO(TraverseDecl(Proto.getParam(I))); - } - } else if (S->hasExplicitResultType()) { - TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); } + if (S->hasExplicitResultType()) + TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); auto *T = Proto.getTypePtr(); - for (const auto &E : T->exceptions()) { + for (const auto &E : T->exceptions()) TRY_TO(TraverseType(E)); - } if (Expr *NE = T->getNoexceptExpr()) TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(NE); - } - ReturnValue = TRAVERSE_STMT_BASE(LambdaBody, LambdaExpr, S, Queue); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody()); + } ShouldVisitChildren = false; }) @@ -2854,6 +2864,36 @@ bool RecursiveASTVisitor<Derived>::VisitOMPProcBindClause(OMPProcBindClause *) { } template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPUnifiedAddressClause( + OMPUnifiedAddressClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPUnifiedSharedMemoryClause( + OMPUnifiedSharedMemoryClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPReverseOffloadClause( + OMPReverseOffloadClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPDynamicAllocatorsClause( + OMPDynamicAllocatorsClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPAtomicDefaultMemOrderClause( + OMPAtomicDefaultMemOrderClause *) { + return true; +} + +template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) { TRY_TO(VisitOMPClauseWithPreInit(C)); diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index aa0f88b71023..ff5baa21adff 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -89,6 +89,8 @@ protected: llvm_unreachable("Stmts cannot be released with regular 'delete'."); } + //===--- Statement bitfields classes ---===// + class StmtBitfields { friend class Stmt; @@ -97,22 +99,186 @@ protected: }; enum { NumStmtBits = 8 }; + class NullStmtBitfields { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend class NullStmt; + + unsigned : NumStmtBits; + + /// True if the null statement was preceded by an empty macro, e.g: + /// @code + /// #define CALL(x) + /// CALL(0); + /// @endcode + unsigned HasLeadingEmptyMacro : 1; + + /// The location of the semi-colon. + SourceLocation SemiLoc; + }; + class CompoundStmtBitfields { + friend class ASTStmtReader; friend class CompoundStmt; unsigned : NumStmtBits; unsigned NumStmts : 32 - NumStmtBits; + + /// The location of the opening "{". + SourceLocation LBraceLoc; + }; + + class LabelStmtBitfields { + friend class LabelStmt; + + unsigned : NumStmtBits; + + SourceLocation IdentLoc; + }; + + class AttributedStmtBitfields { + friend class ASTStmtReader; + friend class AttributedStmt; + + unsigned : NumStmtBits; + + /// Number of attributes. + unsigned NumAttrs : 32 - NumStmtBits; + + /// The location of the attribute. + SourceLocation AttrLoc; }; class IfStmtBitfields { + friend class ASTStmtReader; friend class IfStmt; unsigned : NumStmtBits; + /// True if this if statement is a constexpr if. unsigned IsConstexpr : 1; + + /// True if this if statement has storage for an else statement. + unsigned HasElse : 1; + + /// True if this if statement has storage for a variable declaration. + unsigned HasVar : 1; + + /// True if this if statement has storage for an init statement. + unsigned HasInit : 1; + + /// The location of the "if". + SourceLocation IfLoc; }; + class SwitchStmtBitfields { + friend class SwitchStmt; + + unsigned : NumStmtBits; + + /// True if the SwitchStmt has storage for an init statement. + unsigned HasInit : 1; + + /// True if the SwitchStmt has storage for a condition variable. + unsigned HasVar : 1; + + /// If the SwitchStmt is a switch on an enum value, records whether all + /// the enum values were covered by CaseStmts. The coverage information + /// value is meant to be a hint for possible clients. + unsigned AllEnumCasesCovered : 1; + + /// The location of the "switch". + SourceLocation SwitchLoc; + }; + + class WhileStmtBitfields { + friend class ASTStmtReader; + friend class WhileStmt; + + unsigned : NumStmtBits; + + /// True if the WhileStmt has storage for a condition variable. + unsigned HasVar : 1; + + /// The location of the "while". + SourceLocation WhileLoc; + }; + + class DoStmtBitfields { + friend class DoStmt; + + unsigned : NumStmtBits; + + /// The location of the "do". + SourceLocation DoLoc; + }; + + class ForStmtBitfields { + friend class ForStmt; + + unsigned : NumStmtBits; + + /// The location of the "for". + SourceLocation ForLoc; + }; + + class GotoStmtBitfields { + friend class GotoStmt; + friend class IndirectGotoStmt; + + unsigned : NumStmtBits; + + /// The location of the "goto". + SourceLocation GotoLoc; + }; + + class ContinueStmtBitfields { + friend class ContinueStmt; + + unsigned : NumStmtBits; + + /// The location of the "continue". + SourceLocation ContinueLoc; + }; + + class BreakStmtBitfields { + friend class BreakStmt; + + unsigned : NumStmtBits; + + /// The location of the "break". + SourceLocation BreakLoc; + }; + + class ReturnStmtBitfields { + friend class ReturnStmt; + + unsigned : NumStmtBits; + + /// True if this ReturnStmt has storage for an NRVO candidate. + unsigned HasNRVOCandidate : 1; + + /// The location of the "return". + SourceLocation RetLoc; + }; + + class SwitchCaseBitfields { + friend class SwitchCase; + friend class CaseStmt; + + unsigned : NumStmtBits; + + /// Used by CaseStmt to store whether it is a case statement + /// of the form case LHS ... RHS (a GNU extension). + unsigned CaseStmtIsGNURange : 1; + + /// The location of the "case" or "default" keyword. + SourceLocation KeywordLoc; + }; + + //===--- Expression bitfields classes ---===// + class ExprBitfields { friend class ASTStmtReader; // deserialization friend class AtomicExpr; // ctor @@ -146,14 +312,40 @@ protected: unsigned InstantiationDependent : 1; unsigned ContainsUnexpandedParameterPack : 1; }; - enum { NumExprBits = 17 }; + enum { NumExprBits = NumStmtBits + 9 }; - class CharacterLiteralBitfields { - friend class CharacterLiteral; + class PredefinedExprBitfields { + friend class ASTStmtReader; + friend class PredefinedExpr; unsigned : NumExprBits; - unsigned Kind : 3; + /// The kind of this PredefinedExpr. One of the enumeration values + /// in PredefinedExpr::IdentKind. + unsigned Kind : 4; + + /// True if this PredefinedExpr has a trailing "StringLiteral *" + /// for the predefined identifier. + unsigned HasFunctionName : 1; + + /// The location of this PredefinedExpr. + SourceLocation Loc; + }; + + class DeclRefExprBitfields { + friend class ASTStmtReader; // deserialization + friend class DeclRefExpr; + + unsigned : NumExprBits; + + unsigned HasQualifier : 1; + unsigned HasTemplateKWAndArgsInfo : 1; + unsigned HasFoundDecl : 1; + unsigned HadMultipleCandidates : 1; + unsigned RefersToEnclosingVariableOrCapture : 1; + + /// The location of the declaration name itself. + SourceLocation Loc; }; enum APFloatSemantics { @@ -174,26 +366,111 @@ protected: unsigned IsExact : 1; }; + class StringLiteralBitfields { + friend class ASTStmtReader; + friend class StringLiteral; + + unsigned : NumExprBits; + + /// The kind of this string literal. + /// One of the enumeration values of StringLiteral::StringKind. + unsigned Kind : 3; + + /// The width of a single character in bytes. Only values of 1, 2, + /// and 4 bytes are supported. StringLiteral::mapCharByteWidth maps + /// the target + string kind to the appropriate CharByteWidth. + unsigned CharByteWidth : 3; + + unsigned IsPascal : 1; + + /// The number of concatenated token this string is made of. + /// This is the number of trailing SourceLocation. + unsigned NumConcatenated; + }; + + class CharacterLiteralBitfields { + friend class CharacterLiteral; + + unsigned : NumExprBits; + + unsigned Kind : 3; + }; + + class UnaryOperatorBitfields { + friend class UnaryOperator; + + unsigned : NumExprBits; + + unsigned Opc : 5; + unsigned CanOverflow : 1; + + SourceLocation Loc; + }; + class UnaryExprOrTypeTraitExprBitfields { friend class UnaryExprOrTypeTraitExpr; unsigned : NumExprBits; - unsigned Kind : 2; + unsigned Kind : 3; unsigned IsType : 1; // true if operand is a type, false if an expression. }; - class DeclRefExprBitfields { - friend class ASTStmtReader; // deserialization - friend class DeclRefExpr; + class ArraySubscriptExprBitfields { + friend class ArraySubscriptExpr; unsigned : NumExprBits; - unsigned HasQualifier : 1; + SourceLocation RBracketLoc; + }; + + class CallExprBitfields { + friend class CallExpr; + + unsigned : NumExprBits; + + unsigned NumPreArgs : 1; + + /// True if the callee of the call expression was found using ADL. + unsigned UsesADL : 1; + + /// Padding used to align OffsetToTrailingObjects to a byte multiple. + unsigned : 24 - 2 - NumExprBits; + + /// The offset in bytes from the this pointer to the start of the + /// trailing objects belonging to CallExpr. Intentionally byte sized + /// for faster access. + unsigned OffsetToTrailingObjects : 8; + }; + enum { NumCallExprBits = 32 }; + + class MemberExprBitfields { + friend class MemberExpr; + + unsigned : NumExprBits; + + /// IsArrow - True if this is "X->F", false if this is "X.F". + unsigned IsArrow : 1; + + /// True if this member expression used a nested-name-specifier to + /// refer to the member, e.g., "x->Base::f", or found its member via + /// a using declaration. When true, a MemberExprNameQualifier + /// structure is allocated immediately after the MemberExpr. + unsigned HasQualifierOrFoundDecl : 1; + + /// True if this member expression specified a template keyword + /// and/or a template argument list explicitly, e.g., x->f<int>, + /// x->template f, x->template f<int>. + /// When true, an ASTTemplateKWAndArgsInfo structure and its + /// TemplateArguments (if any) are present. unsigned HasTemplateKWAndArgsInfo : 1; - unsigned HasFoundDecl : 1; + + /// True if this member expression refers to a method that + /// was resolved from an overloaded set having size greater than 1. unsigned HadMultipleCandidates : 1; - unsigned RefersToEnclosingVariableOrCapture : 1; + + /// This is the location of the -> or . in the expression. + SourceLocation OperatorLoc; }; class CastExprBitfields { @@ -204,27 +481,44 @@ protected: unsigned Kind : 6; unsigned PartOfExplicitCast : 1; // Only set for ImplicitCastExpr. - unsigned BasePathIsEmpty : 1; + + /// The number of CXXBaseSpecifiers in the cast. 14 bits would be enough + /// here. ([implimits] Direct and indirect base classes [16384]). + unsigned BasePathSize; }; - class CallExprBitfields { - friend class CallExpr; + class BinaryOperatorBitfields { + friend class BinaryOperator; unsigned : NumExprBits; - unsigned NumPreArgs : 1; + unsigned Opc : 6; + + /// This is only meaningful for operations on floating point + /// types and 0 otherwise. + unsigned FPFeatures : 3; + + SourceLocation OpLoc; }; - class ExprWithCleanupsBitfields { - friend class ASTStmtReader; // deserialization - friend class ExprWithCleanups; + class InitListExprBitfields { + friend class InitListExpr; unsigned : NumExprBits; - // When false, it must not have side effects. - unsigned CleanupsHaveSideEffects : 1; + /// Whether this initializer list originally had a GNU array-range + /// designator in it. This is a temporary marker used by CodeGen. + unsigned HadArrayRangeDesignator : 1; + }; - unsigned NumObjects : 32 - 1 - NumExprBits; + class ParenListExprBitfields { + friend class ASTStmtReader; + friend class ParenListExpr; + + unsigned : NumExprBits; + + /// The number of expressions in the paren list. + unsigned NumExprs; }; class PseudoObjectExprBitfields { @@ -239,32 +533,153 @@ protected: unsigned ResultIndex : 32 - 8 - NumExprBits; }; - class OpaqueValueExprBitfields { - friend class OpaqueValueExpr; + //===--- C++ Expression bitfields classes ---===// + + class CXXOperatorCallExprBitfields { + friend class ASTStmtReader; + friend class CXXOperatorCallExpr; + + unsigned : NumCallExprBits; + + /// The kind of this overloaded operator. One of the enumerator + /// value of OverloadedOperatorKind. + unsigned OperatorKind : 6; + + // Only meaningful for floating point types. + unsigned FPFeatures : 3; + }; + + class CXXBoolLiteralExprBitfields { + friend class CXXBoolLiteralExpr; unsigned : NumExprBits; - /// The OVE is a unique semantic reference to its source expressio if this - /// bit is set to true. - unsigned IsUnique : 1; + /// The value of the boolean literal. + unsigned Value : 1; + + /// The location of the boolean literal. + SourceLocation Loc; }; - class ObjCIndirectCopyRestoreExprBitfields { - friend class ObjCIndirectCopyRestoreExpr; + class CXXNullPtrLiteralExprBitfields { + friend class CXXNullPtrLiteralExpr; unsigned : NumExprBits; - unsigned ShouldCopy : 1; + /// The location of the null pointer literal. + SourceLocation Loc; }; - class InitListExprBitfields { - friend class InitListExpr; + class CXXThisExprBitfields { + friend class CXXThisExpr; unsigned : NumExprBits; - /// Whether this initializer list originally had a GNU array-range - /// designator in it. This is a temporary marker used by CodeGen. - unsigned HadArrayRangeDesignator : 1; + /// Whether this is an implicit "this". + unsigned IsImplicit : 1; + + /// The location of the "this". + SourceLocation Loc; + }; + + class CXXThrowExprBitfields { + friend class ASTStmtReader; + friend class CXXThrowExpr; + + unsigned : NumExprBits; + + /// Whether the thrown variable (if any) is in scope. + unsigned IsThrownVariableInScope : 1; + + /// The location of the "throw". + SourceLocation ThrowLoc; + }; + + class CXXDefaultArgExprBitfields { + friend class ASTStmtReader; + friend class CXXDefaultArgExpr; + + unsigned : NumExprBits; + + /// The location where the default argument expression was used. + SourceLocation Loc; + }; + + class CXXDefaultInitExprBitfields { + friend class ASTStmtReader; + friend class CXXDefaultInitExpr; + + unsigned : NumExprBits; + + /// The location where the default initializer expression was used. + SourceLocation Loc; + }; + + class CXXScalarValueInitExprBitfields { + friend class ASTStmtReader; + friend class CXXScalarValueInitExpr; + + unsigned : NumExprBits; + + SourceLocation RParenLoc; + }; + + class CXXNewExprBitfields { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend class CXXNewExpr; + + unsigned : NumExprBits; + + /// Was the usage ::new, i.e. is the global new to be used? + unsigned IsGlobalNew : 1; + + /// Do we allocate an array? If so, the first trailing "Stmt *" is the + /// size expression. + unsigned IsArray : 1; + + /// Should the alignment be passed to the allocation function? + unsigned ShouldPassAlignment : 1; + + /// If this is an array allocation, does the usual deallocation + /// function for the allocated type want to know the allocated size? + unsigned UsualArrayDeleteWantsSize : 1; + + /// What kind of initializer do we have? Could be none, parens, or braces. + /// In storage, we distinguish between "none, and no initializer expr", and + /// "none, but an implicit initializer expr". + unsigned StoredInitializationStyle : 2; + + /// True if the allocated type was expressed as a parenthesized type-id. + unsigned IsParenTypeId : 1; + + /// The number of placement new arguments. + unsigned NumPlacementArgs; + }; + + class CXXDeleteExprBitfields { + friend class ASTStmtReader; + friend class CXXDeleteExpr; + + unsigned : NumExprBits; + + /// Is this a forced global delete, i.e. "::delete"? + unsigned GlobalDelete : 1; + + /// Is this the array form of delete, i.e. "delete[]"? + unsigned ArrayForm : 1; + + /// ArrayFormAsWritten can be different from ArrayForm if 'delete' is + /// applied to pointer-to-array type (ArrayFormAsWritten will be false + /// while ArrayForm will be true). + unsigned ArrayFormAsWritten : 1; + + /// Does the usual deallocation function for the element type require + /// a size_t argument? + unsigned UsualArrayDeleteWantsSize : 1; + + /// Location of the expression. + SourceLocation Loc; }; class TypeTraitExprBitfields { @@ -285,6 +700,154 @@ protected: unsigned NumArgs : 32 - 8 - 1 - NumExprBits; }; + class DependentScopeDeclRefExprBitfields { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend class DependentScopeDeclRefExpr; + + unsigned : NumExprBits; + + /// Whether the name includes info for explicit template + /// keyword and arguments. + unsigned HasTemplateKWAndArgsInfo : 1; + }; + + class CXXConstructExprBitfields { + friend class ASTStmtReader; + friend class CXXConstructExpr; + + unsigned : NumExprBits; + + unsigned Elidable : 1; + unsigned HadMultipleCandidates : 1; + unsigned ListInitialization : 1; + unsigned StdInitListInitialization : 1; + unsigned ZeroInitialization : 1; + unsigned ConstructionKind : 3; + + SourceLocation Loc; + }; + + class ExprWithCleanupsBitfields { + friend class ASTStmtReader; // deserialization + friend class ExprWithCleanups; + + unsigned : NumExprBits; + + // When false, it must not have side effects. + unsigned CleanupsHaveSideEffects : 1; + + unsigned NumObjects : 32 - 1 - NumExprBits; + }; + + class CXXUnresolvedConstructExprBitfields { + friend class ASTStmtReader; + friend class CXXUnresolvedConstructExpr; + + unsigned : NumExprBits; + + /// The number of arguments used to construct the type. + unsigned NumArgs; + }; + + class CXXDependentScopeMemberExprBitfields { + friend class ASTStmtReader; + friend class CXXDependentScopeMemberExpr; + + unsigned : NumExprBits; + + /// Whether this member expression used the '->' operator or + /// the '.' operator. + unsigned IsArrow : 1; + + /// Whether this member expression has info for explicit template + /// keyword and arguments. + unsigned HasTemplateKWAndArgsInfo : 1; + + /// See getFirstQualifierFoundInScope() and the comment listing + /// the trailing objects. + unsigned HasFirstQualifierFoundInScope : 1; + + /// The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + }; + + class OverloadExprBitfields { + friend class ASTStmtReader; + friend class OverloadExpr; + + unsigned : NumExprBits; + + /// Whether the name includes info for explicit template + /// keyword and arguments. + unsigned HasTemplateKWAndArgsInfo : 1; + + /// Padding used by the derived classes to store various bits. If you + /// need to add some data here, shrink this padding and add your data + /// above. NumOverloadExprBits also needs to be updated. + unsigned : 32 - NumExprBits - 1; + + /// The number of results. + unsigned NumResults; + }; + enum { NumOverloadExprBits = NumExprBits + 1 }; + + class UnresolvedLookupExprBitfields { + friend class ASTStmtReader; + friend class UnresolvedLookupExpr; + + unsigned : NumOverloadExprBits; + + /// True if these lookup results should be extended by + /// argument-dependent lookup if this is the operand of a function call. + unsigned RequiresADL : 1; + + /// True if these lookup results are overloaded. This is pretty trivially + /// rederivable if we urgently need to kill this field. + unsigned Overloaded : 1; + }; + static_assert(sizeof(UnresolvedLookupExprBitfields) <= 4, + "UnresolvedLookupExprBitfields must be <= than 4 bytes to" + "avoid trashing OverloadExprBitfields::NumResults!"); + + class UnresolvedMemberExprBitfields { + friend class ASTStmtReader; + friend class UnresolvedMemberExpr; + + unsigned : NumOverloadExprBits; + + /// Whether this member expression used the '->' operator or + /// the '.' operator. + unsigned IsArrow : 1; + + /// Whether the lookup results contain an unresolved using declaration. + unsigned HasUnresolvedUsing : 1; + }; + static_assert(sizeof(UnresolvedMemberExprBitfields) <= 4, + "UnresolvedMemberExprBitfields must be <= than 4 bytes to" + "avoid trashing OverloadExprBitfields::NumResults!"); + + class CXXNoexceptExprBitfields { + friend class ASTStmtReader; + friend class CXXNoexceptExpr; + + unsigned : NumExprBits; + + unsigned Value : 1; + }; + + class SubstNonTypeTemplateParmExprBitfields { + friend class ASTStmtReader; + friend class SubstNonTypeTemplateParmExpr; + + unsigned : NumExprBits; + + /// The location of the non-type template parameter reference. + SourceLocation NameLoc; + }; + + //===--- C++ Coroutines TS bitfields classes ---===// + class CoawaitExprBitfields { friend class CoawaitExpr; @@ -293,24 +856,99 @@ protected: unsigned IsImplicit : 1; }; + //===--- Obj-C Expression bitfields classes ---===// + + class ObjCIndirectCopyRestoreExprBitfields { + friend class ObjCIndirectCopyRestoreExpr; + + unsigned : NumExprBits; + + unsigned ShouldCopy : 1; + }; + + //===--- Clang Extensions bitfields classes ---===// + + class OpaqueValueExprBitfields { + friend class ASTStmtReader; + friend class OpaqueValueExpr; + + unsigned : NumExprBits; + + /// The OVE is a unique semantic reference to its source expression if this + /// bit is set to true. + unsigned IsUnique : 1; + + SourceLocation Loc; + }; + union { + // Same order as in StmtNodes.td. + // Statements StmtBitfields StmtBits; + NullStmtBitfields NullStmtBits; CompoundStmtBitfields CompoundStmtBits; + LabelStmtBitfields LabelStmtBits; + AttributedStmtBitfields AttributedStmtBits; IfStmtBitfields IfStmtBits; + SwitchStmtBitfields SwitchStmtBits; + WhileStmtBitfields WhileStmtBits; + DoStmtBitfields DoStmtBits; + ForStmtBitfields ForStmtBits; + GotoStmtBitfields GotoStmtBits; + ContinueStmtBitfields ContinueStmtBits; + BreakStmtBitfields BreakStmtBits; + ReturnStmtBitfields ReturnStmtBits; + SwitchCaseBitfields SwitchCaseBits; + + // Expressions ExprBitfields ExprBits; - CharacterLiteralBitfields CharacterLiteralBits; + PredefinedExprBitfields PredefinedExprBits; + DeclRefExprBitfields DeclRefExprBits; FloatingLiteralBitfields FloatingLiteralBits; + StringLiteralBitfields StringLiteralBits; + CharacterLiteralBitfields CharacterLiteralBits; + UnaryOperatorBitfields UnaryOperatorBits; UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits; - DeclRefExprBitfields DeclRefExprBits; - CastExprBitfields CastExprBits; + ArraySubscriptExprBitfields ArraySubscriptExprBits; CallExprBitfields CallExprBits; - ExprWithCleanupsBitfields ExprWithCleanupsBits; - PseudoObjectExprBitfields PseudoObjectExprBits; - OpaqueValueExprBitfields OpaqueValueExprBits; - ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; + MemberExprBitfields MemberExprBits; + CastExprBitfields CastExprBits; + BinaryOperatorBitfields BinaryOperatorBits; InitListExprBitfields InitListExprBits; + ParenListExprBitfields ParenListExprBits; + PseudoObjectExprBitfields PseudoObjectExprBits; + + // C++ Expressions + CXXOperatorCallExprBitfields CXXOperatorCallExprBits; + CXXBoolLiteralExprBitfields CXXBoolLiteralExprBits; + CXXNullPtrLiteralExprBitfields CXXNullPtrLiteralExprBits; + CXXThisExprBitfields CXXThisExprBits; + CXXThrowExprBitfields CXXThrowExprBits; + CXXDefaultArgExprBitfields CXXDefaultArgExprBits; + CXXDefaultInitExprBitfields CXXDefaultInitExprBits; + CXXScalarValueInitExprBitfields CXXScalarValueInitExprBits; + CXXNewExprBitfields CXXNewExprBits; + CXXDeleteExprBitfields CXXDeleteExprBits; TypeTraitExprBitfields TypeTraitExprBits; + DependentScopeDeclRefExprBitfields DependentScopeDeclRefExprBits; + CXXConstructExprBitfields CXXConstructExprBits; + ExprWithCleanupsBitfields ExprWithCleanupsBits; + CXXUnresolvedConstructExprBitfields CXXUnresolvedConstructExprBits; + CXXDependentScopeMemberExprBitfields CXXDependentScopeMemberExprBits; + OverloadExprBitfields OverloadExprBits; + UnresolvedLookupExprBitfields UnresolvedLookupExprBits; + UnresolvedMemberExprBitfields UnresolvedMemberExprBits; + CXXNoexceptExprBitfields CXXNoexceptExprBits; + SubstNonTypeTemplateParmExprBitfields SubstNonTypeTemplateParmExprBits; + + // C++ Coroutines TS expressions CoawaitExprBitfields CoawaitBits; + + // Obj-C Expressions + ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; + + // Clang Extensions + OpaqueValueExprBitfields OpaqueValueExprBits; }; public: @@ -380,7 +1018,7 @@ protected: public: Stmt(StmtClass SC) { - static_assert(sizeof(*this) == sizeof(void *), + static_assert(sizeof(*this) <= 8, "changing bitfields changed sizeof(Stmt)"); static_assert(sizeof(*this) % alignof(void *) == 0, "Insufficient alignment!"); @@ -398,8 +1036,8 @@ public: /// value objects created/interpreted by SourceManager. We assume AST /// clients will have a pointer to the respective SourceManager. SourceRange getSourceRange() const LLVM_READONLY; - SourceLocation getLocStart() const LLVM_READONLY; - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; // global temp stats (until we have a per-module visitor) static void addStmtClass(const StmtClass s); @@ -413,6 +1051,9 @@ public: void dump(raw_ostream &OS, SourceManager &SM) const; void dump(raw_ostream &OS) const; + /// \return Unique reproducible object identifier + int64_t getID(const ASTContext &Context) const; + /// dumpColor - same as dump(), but forces color highlighting. void dumpColor() const; @@ -421,6 +1062,7 @@ public: void dumpPretty(const ASTContext &Context) const; void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation = 0, + StringRef NewlineSymbol = "\n", const ASTContext *Context = nullptr) const; /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only @@ -511,9 +1153,7 @@ public: /// isSingleDecl - This method returns true if this DeclStmt refers /// to a single Decl. - bool isSingleDecl() const { - return DG.isSingleDecl(); - } + bool isSingleDecl() const { return DG.isSingleDecl(); } const Decl *getSingleDecl() const { return DG.getSingleDecl(); } Decl *getSingleDecl() { return DG.getSingleDecl(); } @@ -522,13 +1162,11 @@ public: DeclGroupRef getDeclGroup() { return DG; } void setDeclGroup(DeclGroupRef DGR) { DG = DGR; } - SourceLocation getStartLoc() const { return StartLoc; } void setStartLoc(SourceLocation L) { StartLoc = L; } SourceLocation getEndLoc() const { return EndLoc; } void setEndLoc(SourceLocation L) { EndLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return StartLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return StartLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == DeclStmtClass; @@ -570,33 +1208,25 @@ public: /// NullStmt - This is the null statement ";": C99 6.8.3p3. /// class NullStmt : public Stmt { - SourceLocation SemiLoc; - - /// True if the null statement was preceded by an empty macro, e.g: - /// @code - /// #define CALL(x) - /// CALL(0); - /// @endcode - bool HasLeadingEmptyMacro = false; - public: - friend class ASTStmtReader; - friend class ASTStmtWriter; - NullStmt(SourceLocation L, bool hasLeadingEmptyMacro = false) - : Stmt(NullStmtClass), SemiLoc(L), - HasLeadingEmptyMacro(hasLeadingEmptyMacro) {} + : Stmt(NullStmtClass) { + NullStmtBits.HasLeadingEmptyMacro = hasLeadingEmptyMacro; + setSemiLoc(L); + } /// Build an empty null statement. explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) {} - SourceLocation getSemiLoc() const { return SemiLoc; } - void setSemiLoc(SourceLocation L) { SemiLoc = L; } + SourceLocation getSemiLoc() const { return NullStmtBits.SemiLoc; } + void setSemiLoc(SourceLocation L) { NullStmtBits.SemiLoc = L; } - bool hasLeadingEmptyMacro() const { return HasLeadingEmptyMacro; } + bool hasLeadingEmptyMacro() const { + return NullStmtBits.HasLeadingEmptyMacro; + } - SourceLocation getLocStart() const LLVM_READONLY { return SemiLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return SemiLoc; } + SourceLocation getBeginLoc() const { return getSemiLoc(); } + SourceLocation getEndLoc() const { return getSemiLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == NullStmtClass; @@ -613,7 +1243,8 @@ class CompoundStmt final : public Stmt, friend class ASTStmtReader; friend TrailingObjects; - SourceLocation LBraceLoc, RBraceLoc; + /// The location of the closing "}". LBraceLoc is stored in CompoundStmtBits. + SourceLocation RBraceLoc; CompoundStmt(ArrayRef<Stmt *> Stmts, SourceLocation LB, SourceLocation RB); explicit CompoundStmt(EmptyShell Empty) : Stmt(CompoundStmtClass, Empty) {} @@ -626,8 +1257,9 @@ public: // Build an empty compound statement with a location. explicit CompoundStmt(SourceLocation Loc) - : Stmt(CompoundStmtClass), LBraceLoc(Loc), RBraceLoc(Loc) { + : Stmt(CompoundStmtClass), RBraceLoc(Loc) { CompoundStmtBits.NumStmts = 0; + CompoundStmtBits.LBraceLoc = Loc; } // Build an empty compound statement. @@ -653,7 +1285,7 @@ public: body_begin()[size() - 1] = S; } - using const_body_iterator = Stmt* const *; + using const_body_iterator = Stmt *const *; using body_const_range = llvm::iterator_range<const_body_iterator>; body_const_range body() const { @@ -695,10 +1327,10 @@ public: return const_reverse_body_iterator(body_begin()); } - SourceLocation getLocStart() const LLVM_READONLY { return LBraceLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RBraceLoc; } + SourceLocation getBeginLoc() const { return CompoundStmtBits.LBraceLoc; } + SourceLocation getEndLoc() const { return RBraceLoc; } - SourceLocation getLBracLoc() const { return LBraceLoc; } + SourceLocation getLBracLoc() const { return CompoundStmtBits.LBraceLoc; } SourceLocation getRBracLoc() const { return RBraceLoc; } static bool classof(const Stmt *T) { @@ -716,36 +1348,40 @@ public: // SwitchCase is the base class for CaseStmt and DefaultStmt, class SwitchCase : public Stmt { protected: - // A pointer to the following CaseStmt or DefaultStmt class, - // used by SwitchStmt. - SwitchCase *NextSwitchCase = nullptr; - SourceLocation KeywordLoc; + /// The location of the ":". SourceLocation ColonLoc; + // The location of the "case" or "default" keyword. Stored in SwitchCaseBits. + // SourceLocation KeywordLoc; + + /// A pointer to the following CaseStmt or DefaultStmt class, + /// used by SwitchStmt. + SwitchCase *NextSwitchCase = nullptr; + SwitchCase(StmtClass SC, SourceLocation KWLoc, SourceLocation ColonLoc) - : Stmt(SC), KeywordLoc(KWLoc), ColonLoc(ColonLoc) {} + : Stmt(SC), ColonLoc(ColonLoc) { + setKeywordLoc(KWLoc); + } SwitchCase(StmtClass SC, EmptyShell) : Stmt(SC) {} public: const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; } - SwitchCase *getNextSwitchCase() { return NextSwitchCase; } - void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; } - SourceLocation getKeywordLoc() const { return KeywordLoc; } - void setKeywordLoc(SourceLocation L) { KeywordLoc = L; } + SourceLocation getKeywordLoc() const { return SwitchCaseBits.KeywordLoc; } + void setKeywordLoc(SourceLocation L) { SwitchCaseBits.KeywordLoc = L; } SourceLocation getColonLoc() const { return ColonLoc; } void setColonLoc(SourceLocation L) { ColonLoc = L; } - Stmt *getSubStmt(); + inline Stmt *getSubStmt(); const Stmt *getSubStmt() const { - return const_cast<SwitchCase*>(this)->getSubStmt(); + return const_cast<SwitchCase *>(this)->getSubStmt(); } - SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const { return getKeywordLoc(); } + inline SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == CaseStmtClass || @@ -753,59 +1389,144 @@ public: } }; -class CaseStmt : public SwitchCase { - SourceLocation EllipsisLoc; - enum { LHS, RHS, SUBSTMT, END_EXPR }; - Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for - // GNU "case 1 ... 4" extension +/// CaseStmt - Represent a case statement. It can optionally be a GNU case +/// statement of the form LHS ... RHS representing a range of cases. +class CaseStmt final + : public SwitchCase, + private llvm::TrailingObjects<CaseStmt, Stmt *, SourceLocation> { + friend TrailingObjects; -public: + // CaseStmt is followed by several trailing objects, some of which optional. + // Note that it would be more convenient to put the optional trailing objects + // at the end but this would impact children(). + // The trailing objects are in order: + // + // * A "Stmt *" for the LHS of the case statement. Always present. + // + // * A "Stmt *" for the RHS of the case statement. This is a GNU extension + // which allow ranges in cases statement of the form LHS ... RHS. + // Present if and only if caseStmtIsGNURange() is true. + // + // * A "Stmt *" for the substatement of the case statement. Always present. + // + // * A SourceLocation for the location of the ... if this is a case statement + // with a range. Present if and only if caseStmtIsGNURange() is true. + enum { LhsOffset = 0, SubStmtOffsetFromRhs = 1 }; + enum { NumMandatoryStmtPtr = 2 }; + + unsigned numTrailingObjects(OverloadToken<Stmt *>) const { + return NumMandatoryStmtPtr + caseStmtIsGNURange(); + } + + unsigned numTrailingObjects(OverloadToken<SourceLocation>) const { + return caseStmtIsGNURange(); + } + + unsigned lhsOffset() const { return LhsOffset; } + unsigned rhsOffset() const { return LhsOffset + caseStmtIsGNURange(); } + unsigned subStmtOffset() const { return rhsOffset() + SubStmtOffsetFromRhs; } + + /// Build a case statement assuming that the storage for the + /// trailing objects has been properly allocated. CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, SourceLocation ellipsisLoc, SourceLocation colonLoc) - : SwitchCase(CaseStmtClass, caseLoc, colonLoc) { - SubExprs[SUBSTMT] = nullptr; - SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs); - SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs); - EllipsisLoc = ellipsisLoc; + : SwitchCase(CaseStmtClass, caseLoc, colonLoc) { + // Handle GNU case statements of the form LHS ... RHS. + bool IsGNURange = rhs != nullptr; + SwitchCaseBits.CaseStmtIsGNURange = IsGNURange; + setLHS(lhs); + setSubStmt(nullptr); + if (IsGNURange) { + setRHS(rhs); + setEllipsisLoc(ellipsisLoc); + } } /// Build an empty switch case statement. - explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass, Empty) {} + explicit CaseStmt(EmptyShell Empty, bool CaseStmtIsGNURange) + : SwitchCase(CaseStmtClass, Empty) { + SwitchCaseBits.CaseStmtIsGNURange = CaseStmtIsGNURange; + } - SourceLocation getCaseLoc() const { return KeywordLoc; } - void setCaseLoc(SourceLocation L) { KeywordLoc = L; } - SourceLocation getEllipsisLoc() const { return EllipsisLoc; } - void setEllipsisLoc(SourceLocation L) { EllipsisLoc = L; } - SourceLocation getColonLoc() const { return ColonLoc; } - void setColonLoc(SourceLocation L) { ColonLoc = L; } +public: + /// Build a case statement. + static CaseStmt *Create(const ASTContext &Ctx, Expr *lhs, Expr *rhs, + SourceLocation caseLoc, SourceLocation ellipsisLoc, + SourceLocation colonLoc); + + /// Build an empty case statement. + static CaseStmt *CreateEmpty(const ASTContext &Ctx, bool CaseStmtIsGNURange); + + /// True if this case statement is of the form case LHS ... RHS, which + /// is a GNU extension. In this case the RHS can be obtained with getRHS() + /// and the location of the ellipsis can be obtained with getEllipsisLoc(). + bool caseStmtIsGNURange() const { return SwitchCaseBits.CaseStmtIsGNURange; } + + SourceLocation getCaseLoc() const { return getKeywordLoc(); } + void setCaseLoc(SourceLocation L) { setKeywordLoc(L); } + + /// Get the location of the ... in a case statement of the form LHS ... RHS. + SourceLocation getEllipsisLoc() const { + return caseStmtIsGNURange() ? *getTrailingObjects<SourceLocation>() + : SourceLocation(); + } - Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); } - Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); } - Stmt *getSubStmt() { return SubExprs[SUBSTMT]; } + /// Set the location of the ... in a case statement of the form LHS ... RHS. + /// Assert that this case statement is of this form. + void setEllipsisLoc(SourceLocation L) { + assert( + caseStmtIsGNURange() && + "setEllipsisLoc but this is not a case stmt of the form LHS ... RHS!"); + *getTrailingObjects<SourceLocation>() = L; + } + + Expr *getLHS() { + return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[lhsOffset()]); + } const Expr *getLHS() const { - return reinterpret_cast<const Expr*>(SubExprs[LHS]); + return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[lhsOffset()]); + } + + void setLHS(Expr *Val) { + getTrailingObjects<Stmt *>()[lhsOffset()] = reinterpret_cast<Stmt *>(Val); + } + + Expr *getRHS() { + return caseStmtIsGNURange() ? reinterpret_cast<Expr *>( + getTrailingObjects<Stmt *>()[rhsOffset()]) + : nullptr; } const Expr *getRHS() const { - return reinterpret_cast<const Expr*>(SubExprs[RHS]); + return caseStmtIsGNURange() ? reinterpret_cast<Expr *>( + getTrailingObjects<Stmt *>()[rhsOffset()]) + : nullptr; } - const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; } + void setRHS(Expr *Val) { + assert(caseStmtIsGNURange() && + "setRHS but this is not a case stmt of the form LHS ... RHS!"); + getTrailingObjects<Stmt *>()[rhsOffset()] = reinterpret_cast<Stmt *>(Val); + } - void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; } - void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast<Stmt*>(Val); } - void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); } + Stmt *getSubStmt() { return getTrailingObjects<Stmt *>()[subStmtOffset()]; } + const Stmt *getSubStmt() const { + return getTrailingObjects<Stmt *>()[subStmtOffset()]; + } - SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } + void setSubStmt(Stmt *S) { + getTrailingObjects<Stmt *>()[subStmtOffset()] = S; + } - SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation getBeginLoc() const { return getKeywordLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { // Handle deeply nested case statements with iteration instead of recursion. const CaseStmt *CS = this; while (const auto *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt())) CS = CS2; - return CS->getSubStmt()->getLocEnd(); + return CS->getSubStmt()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -814,16 +1535,18 @@ public: // Iterators child_range children() { - return child_range(&SubExprs[0], &SubExprs[END_EXPR]); + return child_range(getTrailingObjects<Stmt *>(), + getTrailingObjects<Stmt *>() + + numTrailingObjects(OverloadToken<Stmt *>())); } }; class DefaultStmt : public SwitchCase { - Stmt* SubStmt; + Stmt *SubStmt; public: - DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : - SwitchCase(DefaultStmtClass, DL, CL), SubStmt(substmt) {} + DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) + : SwitchCase(DefaultStmtClass, DL, CL), SubStmt(substmt) {} /// Build an empty default statement. explicit DefaultStmt(EmptyShell Empty) @@ -833,59 +1556,70 @@ public: const Stmt *getSubStmt() const { return SubStmt; } void setSubStmt(Stmt *S) { SubStmt = S; } - SourceLocation getDefaultLoc() const { return KeywordLoc; } - void setDefaultLoc(SourceLocation L) { KeywordLoc = L; } - SourceLocation getColonLoc() const { return ColonLoc; } - void setColonLoc(SourceLocation L) { ColonLoc = L; } + SourceLocation getDefaultLoc() const { return getKeywordLoc(); } + void setDefaultLoc(SourceLocation L) { setKeywordLoc(L); } - SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + SourceLocation getBeginLoc() const { return getKeywordLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { + return SubStmt->getEndLoc(); + } static bool classof(const Stmt *T) { return T->getStmtClass() == DefaultStmtClass; } // Iterators - child_range children() { return child_range(&SubStmt, &SubStmt+1); } + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } }; -inline SourceLocation SwitchCase::getLocEnd() const { +SourceLocation SwitchCase::getEndLoc() const { if (const auto *CS = dyn_cast<CaseStmt>(this)) - return CS->getLocEnd(); - return cast<DefaultStmt>(this)->getLocEnd(); + return CS->getEndLoc(); + else if (const auto *DS = dyn_cast<DefaultStmt>(this)) + return DS->getEndLoc(); + llvm_unreachable("SwitchCase is neither a CaseStmt nor a DefaultStmt!"); +} + +Stmt *SwitchCase::getSubStmt() { + if (auto *CS = dyn_cast<CaseStmt>(this)) + return CS->getSubStmt(); + else if (auto *DS = dyn_cast<DefaultStmt>(this)) + return DS->getSubStmt(); + llvm_unreachable("SwitchCase is neither a CaseStmt nor a DefaultStmt!"); } /// LabelStmt - Represents a label, which has a substatement. For example: /// foo: return; class LabelStmt : public Stmt { - SourceLocation IdentLoc; LabelDecl *TheDecl; Stmt *SubStmt; public: + /// Build a label statement. LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt) - : Stmt(LabelStmtClass), IdentLoc(IL), TheDecl(D), SubStmt(substmt) { - static_assert(sizeof(LabelStmt) == - 2 * sizeof(SourceLocation) + 2 * sizeof(void *), - "LabelStmt too big"); + : Stmt(LabelStmtClass), TheDecl(D), SubStmt(substmt) { + setIdentLoc(IL); } - // Build an empty label statement. + /// Build an empty label statement. explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) {} - SourceLocation getIdentLoc() const { return IdentLoc; } + SourceLocation getIdentLoc() const { return LabelStmtBits.IdentLoc; } + void setIdentLoc(SourceLocation L) { LabelStmtBits.IdentLoc = L; } + LabelDecl *getDecl() const { return TheDecl; } void setDecl(LabelDecl *D) { TheDecl = D; } + const char *getName() const; Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } - void setIdentLoc(SourceLocation L) { IdentLoc = L; } void setSubStmt(Stmt *SS) { SubStmt = SS; } - SourceLocation getLocStart() const LLVM_READONLY { return IdentLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + SourceLocation getBeginLoc() const { return getIdentLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { return SubStmt->getEndLoc();} - child_range children() { return child_range(&SubStmt, &SubStmt+1); } + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } static bool classof(const Stmt *T) { return T->getStmtClass() == LabelStmtClass; @@ -903,17 +1637,19 @@ class AttributedStmt final friend TrailingObjects; Stmt *SubStmt; - SourceLocation AttrLoc; - unsigned NumAttrs; - AttributedStmt(SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt) - : Stmt(AttributedStmtClass), SubStmt(SubStmt), AttrLoc(Loc), - NumAttrs(Attrs.size()) { + AttributedStmt(SourceLocation Loc, ArrayRef<const Attr *> Attrs, + Stmt *SubStmt) + : Stmt(AttributedStmtClass), SubStmt(SubStmt) { + AttributedStmtBits.NumAttrs = Attrs.size(); + AttributedStmtBits.AttrLoc = Loc; std::copy(Attrs.begin(), Attrs.end(), getAttrArrayPtr()); } explicit AttributedStmt(EmptyShell Empty, unsigned NumAttrs) - : Stmt(AttributedStmtClass, Empty), NumAttrs(NumAttrs) { + : Stmt(AttributedStmtClass, Empty) { + AttributedStmtBits.NumAttrs = NumAttrs; + AttributedStmtBits.AttrLoc = SourceLocation{}; std::fill_n(getAttrArrayPtr(), NumAttrs, nullptr); } @@ -924,21 +1660,21 @@ class AttributedStmt final public: static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc, - ArrayRef<const Attr*> Attrs, Stmt *SubStmt); + ArrayRef<const Attr *> Attrs, Stmt *SubStmt); // Build an empty attributed statement. static AttributedStmt *CreateEmpty(const ASTContext &C, unsigned NumAttrs); - SourceLocation getAttrLoc() const { return AttrLoc; } - ArrayRef<const Attr*> getAttrs() const { - return llvm::makeArrayRef(getAttrArrayPtr(), NumAttrs); + SourceLocation getAttrLoc() const { return AttributedStmtBits.AttrLoc; } + ArrayRef<const Attr *> getAttrs() const { + return llvm::makeArrayRef(getAttrArrayPtr(), AttributedStmtBits.NumAttrs); } Stmt *getSubStmt() { return SubStmt; } const Stmt *getSubStmt() const { return SubStmt; } - SourceLocation getLocStart() const LLVM_READONLY { return AttrLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + SourceLocation getBeginLoc() const { return getAttrLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { return SubStmt->getEndLoc();} child_range children() { return child_range(&SubStmt, &SubStmt + 1); } @@ -948,21 +1684,117 @@ public: }; /// IfStmt - This represents an if/then/else. -class IfStmt : public Stmt { - enum { INIT, VAR, COND, THEN, ELSE, END_EXPR }; - Stmt* SubExprs[END_EXPR]; +class IfStmt final + : public Stmt, + private llvm::TrailingObjects<IfStmt, Stmt *, SourceLocation> { + friend TrailingObjects; + + // IfStmt is followed by several trailing objects, some of which optional. + // Note that it would be more convenient to put the optional trailing + // objects at then end but this would change the order of the children. + // The trailing objects are in order: + // + // * A "Stmt *" for the init statement. + // Present if and only if hasInitStorage(). + // + // * A "Stmt *" for the condition variable. + // Present if and only if hasVarStorage(). This is in fact a "DeclStmt *". + // + // * A "Stmt *" for the condition. + // Always present. This is in fact a "Expr *". + // + // * A "Stmt *" for the then statement. + // Always present. + // + // * A "Stmt *" for the else statement. + // Present if and only if hasElseStorage(). + // + // * A "SourceLocation" for the location of the "else". + // Present if and only if hasElseStorage(). + enum { InitOffset = 0, ThenOffsetFromCond = 1, ElseOffsetFromCond = 2 }; + enum { NumMandatoryStmtPtr = 2 }; + + unsigned numTrailingObjects(OverloadToken<Stmt *>) const { + return NumMandatoryStmtPtr + hasElseStorage() + hasVarStorage() + + hasInitStorage(); + } + + unsigned numTrailingObjects(OverloadToken<SourceLocation>) const { + return hasElseStorage(); + } + + unsigned initOffset() const { return InitOffset; } + unsigned varOffset() const { return InitOffset + hasInitStorage(); } + unsigned condOffset() const { + return InitOffset + hasInitStorage() + hasVarStorage(); + } + unsigned thenOffset() const { return condOffset() + ThenOffsetFromCond; } + unsigned elseOffset() const { return condOffset() + ElseOffsetFromCond; } - SourceLocation IfLoc; - SourceLocation ElseLoc; + /// Build an if/then/else statement. + IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init, + VarDecl *Var, Expr *Cond, Stmt *Then, SourceLocation EL, Stmt *Else); + + /// Build an empty if/then/else statement. + explicit IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit); public: - IfStmt(const ASTContext &C, SourceLocation IL, - bool IsConstexpr, Stmt *init, VarDecl *var, Expr *cond, - Stmt *then, SourceLocation EL = SourceLocation(), - Stmt *elsev = nullptr); + /// Create an IfStmt. + static IfStmt *Create(const ASTContext &Ctx, SourceLocation IL, + bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond, + Stmt *Then, SourceLocation EL = SourceLocation(), + Stmt *Else = nullptr); + + /// Create an empty IfStmt optionally with storage for an else statement, + /// condition variable and init expression. + static IfStmt *CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar, + bool HasInit); - /// Build an empty if/then/else statement - explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) {} + /// True if this IfStmt has the storage for an init statement. + bool hasInitStorage() const { return IfStmtBits.HasInit; } + + /// True if this IfStmt has storage for a variable declaration. + bool hasVarStorage() const { return IfStmtBits.HasVar; } + + /// True if this IfStmt has storage for an else statement. + bool hasElseStorage() const { return IfStmtBits.HasElse; } + + Expr *getCond() { + return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]); + } + + const Expr *getCond() const { + return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]); + } + + void setCond(Expr *Cond) { + getTrailingObjects<Stmt *>()[condOffset()] = reinterpret_cast<Stmt *>(Cond); + } + + Stmt *getThen() { return getTrailingObjects<Stmt *>()[thenOffset()]; } + const Stmt *getThen() const { + return getTrailingObjects<Stmt *>()[thenOffset()]; + } + + void setThen(Stmt *Then) { + getTrailingObjects<Stmt *>()[thenOffset()] = Then; + } + + Stmt *getElse() { + return hasElseStorage() ? getTrailingObjects<Stmt *>()[elseOffset()] + : nullptr; + } + + const Stmt *getElse() const { + return hasElseStorage() ? getTrailingObjects<Stmt *>()[elseOffset()] + : nullptr; + } + + void setElse(Stmt *Else) { + assert(hasElseStorage() && + "This if statement has no storage for an else statement!"); + getTrailingObjects<Stmt *>()[elseOffset()] = Else; + } /// Retrieve the variable declared in this "if" statement, if any. /// @@ -972,52 +1804,77 @@ public: /// printf("x is %d", x); /// } /// \endcode - VarDecl *getConditionVariable() const; - void setConditionVariable(const ASTContext &C, VarDecl *V); + VarDecl *getConditionVariable(); + const VarDecl *getConditionVariable() const { + return const_cast<IfStmt *>(this)->getConditionVariable(); + } + + /// Set the condition variable for this if statement. + /// The if statement must have storage for the condition variable. + void setConditionVariable(const ASTContext &Ctx, VarDecl *V); /// If this IfStmt has a condition variable, return the faux DeclStmt /// associated with the creation of that condition variable. + DeclStmt *getConditionVariableDeclStmt() { + return hasVarStorage() ? static_cast<DeclStmt *>( + getTrailingObjects<Stmt *>()[varOffset()]) + : nullptr; + } + const DeclStmt *getConditionVariableDeclStmt() const { - return reinterpret_cast<DeclStmt*>(SubExprs[VAR]); + return hasVarStorage() ? static_cast<DeclStmt *>( + getTrailingObjects<Stmt *>()[varOffset()]) + : nullptr; } - Stmt *getInit() { return SubExprs[INIT]; } - const Stmt *getInit() const { return SubExprs[INIT]; } - void setInit(Stmt *S) { SubExprs[INIT] = S; } - const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} - void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } - const Stmt *getThen() const { return SubExprs[THEN]; } - void setThen(Stmt *S) { SubExprs[THEN] = S; } - const Stmt *getElse() const { return SubExprs[ELSE]; } - void setElse(Stmt *S) { SubExprs[ELSE] = S; } + Stmt *getInit() { + return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()] + : nullptr; + } - Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } - Stmt *getThen() { return SubExprs[THEN]; } - Stmt *getElse() { return SubExprs[ELSE]; } + const Stmt *getInit() const { + return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()] + : nullptr; + } + + void setInit(Stmt *Init) { + assert(hasInitStorage() && + "This if statement has no storage for an init statement!"); + getTrailingObjects<Stmt *>()[initOffset()] = Init; + } + + SourceLocation getIfLoc() const { return IfStmtBits.IfLoc; } + void setIfLoc(SourceLocation IfLoc) { IfStmtBits.IfLoc = IfLoc; } - SourceLocation getIfLoc() const { return IfLoc; } - void setIfLoc(SourceLocation L) { IfLoc = L; } - SourceLocation getElseLoc() const { return ElseLoc; } - void setElseLoc(SourceLocation L) { ElseLoc = L; } + SourceLocation getElseLoc() const { + return hasElseStorage() ? *getTrailingObjects<SourceLocation>() + : SourceLocation(); + } + + void setElseLoc(SourceLocation ElseLoc) { + assert(hasElseStorage() && + "This if statement has no storage for an else statement!"); + *getTrailingObjects<SourceLocation>() = ElseLoc; + } bool isConstexpr() const { return IfStmtBits.IsConstexpr; } void setConstexpr(bool C) { IfStmtBits.IsConstexpr = C; } bool isObjCAvailabilityCheck() const; - SourceLocation getLocStart() const LLVM_READONLY { return IfLoc; } - - SourceLocation getLocEnd() const LLVM_READONLY { - if (SubExprs[ELSE]) - return SubExprs[ELSE]->getLocEnd(); - else - return SubExprs[THEN]->getLocEnd(); + SourceLocation getBeginLoc() const { return getIfLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { + if (getElse()) + return getElse()->getEndLoc(); + return getThen()->getEndLoc(); } // Iterators over subexpressions. The iterators will include iterating // over the initialization expression referenced by the condition variable. child_range children() { - return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + return child_range(getTrailingObjects<Stmt *>(), + getTrailingObjects<Stmt *>() + + numTrailingObjects(OverloadToken<Stmt *>())); } static bool classof(const Stmt *T) { @@ -1026,22 +1883,102 @@ public: }; /// SwitchStmt - This represents a 'switch' stmt. -class SwitchStmt : public Stmt { - SourceLocation SwitchLoc; - enum { INIT, VAR, COND, BODY, END_EXPR }; - Stmt* SubExprs[END_EXPR]; +class SwitchStmt final : public Stmt, + private llvm::TrailingObjects<SwitchStmt, Stmt *> { + friend TrailingObjects; - // This points to a linked list of case and default statements and, if the - // SwitchStmt is a switch on an enum value, records whether all the enum - // values were covered by CaseStmts. The coverage information value is meant - // to be a hint for possible clients. - llvm::PointerIntPair<SwitchCase *, 1, bool> FirstCase; + /// Points to a linked list of case and default statements. + SwitchCase *FirstCase; -public: - SwitchStmt(const ASTContext &C, Stmt *Init, VarDecl *Var, Expr *cond); + // SwitchStmt is followed by several trailing objects, + // some of which optional. Note that it would be more convenient to + // put the optional trailing objects at the end but this would change + // the order in children(). + // The trailing objects are in order: + // + // * A "Stmt *" for the init statement. + // Present if and only if hasInitStorage(). + // + // * A "Stmt *" for the condition variable. + // Present if and only if hasVarStorage(). This is in fact a "DeclStmt *". + // + // * A "Stmt *" for the condition. + // Always present. This is in fact an "Expr *". + // + // * A "Stmt *" for the body. + // Always present. + enum { InitOffset = 0, BodyOffsetFromCond = 1 }; + enum { NumMandatoryStmtPtr = 2 }; + + unsigned numTrailingObjects(OverloadToken<Stmt *>) const { + return NumMandatoryStmtPtr + hasInitStorage() + hasVarStorage(); + } + + unsigned initOffset() const { return InitOffset; } + unsigned varOffset() const { return InitOffset + hasInitStorage(); } + unsigned condOffset() const { + return InitOffset + hasInitStorage() + hasVarStorage(); + } + unsigned bodyOffset() const { return condOffset() + BodyOffsetFromCond; } + + /// Build a switch statement. + SwitchStmt(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, Expr *Cond); /// Build a empty switch statement. - explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) {} + explicit SwitchStmt(EmptyShell Empty, bool HasInit, bool HasVar); + +public: + /// Create a switch statement. + static SwitchStmt *Create(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, + Expr *Cond); + + /// Create an empty switch statement optionally with storage for + /// an init expression and a condition variable. + static SwitchStmt *CreateEmpty(const ASTContext &Ctx, bool HasInit, + bool HasVar); + + /// True if this SwitchStmt has storage for an init statement. + bool hasInitStorage() const { return SwitchStmtBits.HasInit; } + + /// True if this SwitchStmt has storage for a condition variable. + bool hasVarStorage() const { return SwitchStmtBits.HasVar; } + + Expr *getCond() { + return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]); + } + + const Expr *getCond() const { + return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]); + } + + void setCond(Expr *Cond) { + getTrailingObjects<Stmt *>()[condOffset()] = reinterpret_cast<Stmt *>(Cond); + } + + Stmt *getBody() { return getTrailingObjects<Stmt *>()[bodyOffset()]; } + const Stmt *getBody() const { + return getTrailingObjects<Stmt *>()[bodyOffset()]; + } + + void setBody(Stmt *Body) { + getTrailingObjects<Stmt *>()[bodyOffset()] = Body; + } + + Stmt *getInit() { + return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()] + : nullptr; + } + + const Stmt *getInit() const { + return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()] + : nullptr; + } + + void setInit(Stmt *Init) { + assert(hasInitStorage() && + "This switch statement has no storage for an init statement!"); + getTrailingObjects<Stmt *>()[initOffset()] = Init; + } /// Retrieve the variable declared in this "switch" statement, if any. /// @@ -1052,63 +1989,69 @@ public: /// // ... /// } /// \endcode - VarDecl *getConditionVariable() const; - void setConditionVariable(const ASTContext &C, VarDecl *V); + VarDecl *getConditionVariable(); + const VarDecl *getConditionVariable() const { + return const_cast<SwitchStmt *>(this)->getConditionVariable(); + } + + /// Set the condition variable in this switch statement. + /// The switch statement must have storage for it. + void setConditionVariable(const ASTContext &Ctx, VarDecl *VD); /// If this SwitchStmt has a condition variable, return the faux DeclStmt /// associated with the creation of that condition variable. - const DeclStmt *getConditionVariableDeclStmt() const { - return reinterpret_cast<DeclStmt*>(SubExprs[VAR]); + DeclStmt *getConditionVariableDeclStmt() { + return hasVarStorage() ? static_cast<DeclStmt *>( + getTrailingObjects<Stmt *>()[varOffset()]) + : nullptr; } - Stmt *getInit() { return SubExprs[INIT]; } - const Stmt *getInit() const { return SubExprs[INIT]; } - void setInit(Stmt *S) { SubExprs[INIT] = S; } - const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} - const Stmt *getBody() const { return SubExprs[BODY]; } - const SwitchCase *getSwitchCaseList() const { return FirstCase.getPointer(); } - - Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);} - void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } - Stmt *getBody() { return SubExprs[BODY]; } - void setBody(Stmt *S) { SubExprs[BODY] = S; } - SwitchCase *getSwitchCaseList() { return FirstCase.getPointer(); } + const DeclStmt *getConditionVariableDeclStmt() const { + return hasVarStorage() ? static_cast<DeclStmt *>( + getTrailingObjects<Stmt *>()[varOffset()]) + : nullptr; + } - /// Set the case list for this switch statement. - void setSwitchCaseList(SwitchCase *SC) { FirstCase.setPointer(SC); } + SwitchCase *getSwitchCaseList() { return FirstCase; } + const SwitchCase *getSwitchCaseList() const { return FirstCase; } + void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; } - SourceLocation getSwitchLoc() const { return SwitchLoc; } - void setSwitchLoc(SourceLocation L) { SwitchLoc = L; } + SourceLocation getSwitchLoc() const { return SwitchStmtBits.SwitchLoc; } + void setSwitchLoc(SourceLocation L) { SwitchStmtBits.SwitchLoc = L; } void setBody(Stmt *S, SourceLocation SL) { - SubExprs[BODY] = S; - SwitchLoc = SL; + setBody(S); + setSwitchLoc(SL); } void addSwitchCase(SwitchCase *SC) { - assert(!SC->getNextSwitchCase() - && "case/default already added to a switch"); - SC->setNextSwitchCase(FirstCase.getPointer()); - FirstCase.setPointer(SC); + assert(!SC->getNextSwitchCase() && + "case/default already added to a switch"); + SC->setNextSwitchCase(FirstCase); + FirstCase = SC; } /// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a /// switch over an enum value then all cases have been explicitly covered. - void setAllEnumCasesCovered() { FirstCase.setInt(true); } + void setAllEnumCasesCovered() { SwitchStmtBits.AllEnumCasesCovered = true; } /// Returns true if the SwitchStmt is a switch of an enum value and all cases /// have been explicitly covered. - bool isAllEnumCasesCovered() const { return FirstCase.getInt(); } - - SourceLocation getLocStart() const LLVM_READONLY { return SwitchLoc; } + bool isAllEnumCasesCovered() const { + return SwitchStmtBits.AllEnumCasesCovered; + } - SourceLocation getLocEnd() const LLVM_READONLY { - return SubExprs[BODY] ? SubExprs[BODY]->getLocEnd() : SubExprs[COND]->getLocEnd(); + SourceLocation getBeginLoc() const { return getSwitchLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { + return getBody() ? getBody()->getEndLoc() + : reinterpret_cast<const Stmt *>(getCond())->getEndLoc(); } // Iterators child_range children() { - return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + return child_range(getTrailingObjects<Stmt *>(), + getTrailingObjects<Stmt *>() + + numTrailingObjects(OverloadToken<Stmt *>())); } static bool classof(const Stmt *T) { @@ -1117,17 +2060,75 @@ public: }; /// WhileStmt - This represents a 'while' stmt. -class WhileStmt : public Stmt { - SourceLocation WhileLoc; - enum { VAR, COND, BODY, END_EXPR }; - Stmt* SubExprs[END_EXPR]; +class WhileStmt final : public Stmt, + private llvm::TrailingObjects<WhileStmt, Stmt *> { + friend TrailingObjects; -public: - WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, + // WhileStmt is followed by several trailing objects, + // some of which optional. Note that it would be more + // convenient to put the optional trailing object at the end + // but this would affect children(). + // The trailing objects are in order: + // + // * A "Stmt *" for the condition variable. + // Present if and only if hasVarStorage(). This is in fact a "DeclStmt *". + // + // * A "Stmt *" for the condition. + // Always present. This is in fact an "Expr *". + // + // * A "Stmt *" for the body. + // Always present. + // + enum { VarOffset = 0, BodyOffsetFromCond = 1 }; + enum { NumMandatoryStmtPtr = 2 }; + + unsigned varOffset() const { return VarOffset; } + unsigned condOffset() const { return VarOffset + hasVarStorage(); } + unsigned bodyOffset() const { return condOffset() + BodyOffsetFromCond; } + + unsigned numTrailingObjects(OverloadToken<Stmt *>) const { + return NumMandatoryStmtPtr + hasVarStorage(); + } + + /// Build a while statement. + WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond, Stmt *Body, SourceLocation WL); /// Build an empty while statement. - explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) {} + explicit WhileStmt(EmptyShell Empty, bool HasVar); + +public: + /// Create a while statement. + static WhileStmt *Create(const ASTContext &Ctx, VarDecl *Var, Expr *Cond, + Stmt *Body, SourceLocation WL); + + /// Create an empty while statement optionally with storage for + /// a condition variable. + static WhileStmt *CreateEmpty(const ASTContext &Ctx, bool HasVar); + + /// True if this WhileStmt has storage for a condition variable. + bool hasVarStorage() const { return WhileStmtBits.HasVar; } + + Expr *getCond() { + return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]); + } + + const Expr *getCond() const { + return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]); + } + + void setCond(Expr *Cond) { + getTrailingObjects<Stmt *>()[condOffset()] = reinterpret_cast<Stmt *>(Cond); + } + + Stmt *getBody() { return getTrailingObjects<Stmt *>()[bodyOffset()]; } + const Stmt *getBody() const { + return getTrailingObjects<Stmt *>()[bodyOffset()]; + } + + void setBody(Stmt *Body) { + getTrailingObjects<Stmt *>()[bodyOffset()] = Body; + } /// Retrieve the variable declared in this "while" statement, if any. /// @@ -1137,29 +2138,35 @@ public: /// // ... /// } /// \endcode - VarDecl *getConditionVariable() const; - void setConditionVariable(const ASTContext &C, VarDecl *V); + VarDecl *getConditionVariable(); + const VarDecl *getConditionVariable() const { + return const_cast<WhileStmt *>(this)->getConditionVariable(); + } + + /// Set the condition variable of this while statement. + /// The while statement must have storage for it. + void setConditionVariable(const ASTContext &Ctx, VarDecl *V); /// If this WhileStmt has a condition variable, return the faux DeclStmt /// associated with the creation of that condition variable. - const DeclStmt *getConditionVariableDeclStmt() const { - return reinterpret_cast<DeclStmt*>(SubExprs[VAR]); + DeclStmt *getConditionVariableDeclStmt() { + return hasVarStorage() ? static_cast<DeclStmt *>( + getTrailingObjects<Stmt *>()[varOffset()]) + : nullptr; } - Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } - const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} - void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } - Stmt *getBody() { return SubExprs[BODY]; } - const Stmt *getBody() const { return SubExprs[BODY]; } - void setBody(Stmt *S) { SubExprs[BODY] = S; } - - SourceLocation getWhileLoc() const { return WhileLoc; } - void setWhileLoc(SourceLocation L) { WhileLoc = L; } + const DeclStmt *getConditionVariableDeclStmt() const { + return hasVarStorage() ? static_cast<DeclStmt *>( + getTrailingObjects<Stmt *>()[varOffset()]) + : nullptr; + } - SourceLocation getLocStart() const LLVM_READONLY { return WhileLoc; } + SourceLocation getWhileLoc() const { return WhileStmtBits.WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileStmtBits.WhileLoc = L; } - SourceLocation getLocEnd() const LLVM_READONLY { - return SubExprs[BODY]->getLocEnd(); + SourceLocation getBeginLoc() const { return getWhileLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { + return getBody()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -1168,46 +2175,51 @@ public: // Iterators child_range children() { - return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + return child_range(getTrailingObjects<Stmt *>(), + getTrailingObjects<Stmt *>() + + numTrailingObjects(OverloadToken<Stmt *>())); } }; /// DoStmt - This represents a 'do/while' stmt. class DoStmt : public Stmt { - SourceLocation DoLoc; enum { BODY, COND, END_EXPR }; - Stmt* SubExprs[END_EXPR]; + Stmt *SubExprs[END_EXPR]; SourceLocation WhileLoc; - SourceLocation RParenLoc; // Location of final ')' in do stmt condition. + SourceLocation RParenLoc; // Location of final ')' in do stmt condition. public: - DoStmt(Stmt *body, Expr *cond, SourceLocation DL, SourceLocation WL, + DoStmt(Stmt *Body, Expr *Cond, SourceLocation DL, SourceLocation WL, SourceLocation RP) - : Stmt(DoStmtClass), DoLoc(DL), WhileLoc(WL), RParenLoc(RP) { - SubExprs[COND] = reinterpret_cast<Stmt*>(cond); - SubExprs[BODY] = body; + : Stmt(DoStmtClass), WhileLoc(WL), RParenLoc(RP) { + setCond(Cond); + setBody(Body); + setDoLoc(DL); } /// Build an empty do-while statement. explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) {} - Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } - const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} - void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + Expr *getCond() { return reinterpret_cast<Expr *>(SubExprs[COND]); } + const Expr *getCond() const { + return reinterpret_cast<Expr *>(SubExprs[COND]); + } + + void setCond(Expr *Cond) { SubExprs[COND] = reinterpret_cast<Stmt *>(Cond); } + Stmt *getBody() { return SubExprs[BODY]; } const Stmt *getBody() const { return SubExprs[BODY]; } - void setBody(Stmt *S) { SubExprs[BODY] = S; } + void setBody(Stmt *Body) { SubExprs[BODY] = Body; } - SourceLocation getDoLoc() const { return DoLoc; } - void setDoLoc(SourceLocation L) { DoLoc = L; } + SourceLocation getDoLoc() const { return DoStmtBits.DoLoc; } + void setDoLoc(SourceLocation L) { DoStmtBits.DoLoc = L; } SourceLocation getWhileLoc() const { return WhileLoc; } void setWhileLoc(SourceLocation L) { WhileLoc = L; } - SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return DoLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const { return getDoLoc(); } + SourceLocation getEndLoc() const { return getRParenLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == DoStmtClass; @@ -1215,7 +2227,7 @@ public: // Iterators child_range children() { - return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + return child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; @@ -1223,7 +2235,6 @@ public: /// the init/cond/inc parts of the ForStmt will be null if they were not /// specified in the source. class ForStmt : public Stmt { - SourceLocation ForLoc; enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt. SourceLocation LParenLoc, RParenLoc; @@ -1269,18 +2280,15 @@ public: void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); } void setBody(Stmt *S) { SubExprs[BODY] = S; } - SourceLocation getForLoc() const { return ForLoc; } - void setForLoc(SourceLocation L) { ForLoc = L; } + SourceLocation getForLoc() const { return ForStmtBits.ForLoc; } + void setForLoc(SourceLocation L) { ForStmtBits.ForLoc = L; } SourceLocation getLParenLoc() const { return LParenLoc; } void setLParenLoc(SourceLocation L) { LParenLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; } - - SourceLocation getLocEnd() const LLVM_READONLY { - return SubExprs[BODY]->getLocEnd(); - } + SourceLocation getBeginLoc() const { return getForLoc(); } + SourceLocation getEndLoc() const { return getBody()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ForStmtClass; @@ -1295,12 +2303,13 @@ public: /// GotoStmt - This represents a direct goto. class GotoStmt : public Stmt { LabelDecl *Label; - SourceLocation GotoLoc; SourceLocation LabelLoc; public: GotoStmt(LabelDecl *label, SourceLocation GL, SourceLocation LL) - : Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {} + : Stmt(GotoStmtClass), Label(label), LabelLoc(LL) { + setGotoLoc(GL); + } /// Build an empty goto statement. explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) {} @@ -1308,13 +2317,13 @@ public: LabelDecl *getLabel() const { return Label; } void setLabel(LabelDecl *D) { Label = D; } - SourceLocation getGotoLoc() const { return GotoLoc; } - void setGotoLoc(SourceLocation L) { GotoLoc = L; } + SourceLocation getGotoLoc() const { return GotoStmtBits.GotoLoc; } + void setGotoLoc(SourceLocation L) { GotoStmtBits.GotoLoc = L; } SourceLocation getLabelLoc() const { return LabelLoc; } void setLabelLoc(SourceLocation L) { LabelLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return GotoLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return LabelLoc; } + SourceLocation getBeginLoc() const { return getGotoLoc(); } + SourceLocation getEndLoc() const { return getLabelLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == GotoStmtClass; @@ -1328,62 +2337,64 @@ public: /// IndirectGotoStmt - This represents an indirect goto. class IndirectGotoStmt : public Stmt { - SourceLocation GotoLoc; SourceLocation StarLoc; Stmt *Target; public: - IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, - Expr *target) - : Stmt(IndirectGotoStmtClass), GotoLoc(gotoLoc), StarLoc(starLoc), - Target((Stmt*)target) {} + IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, Expr *target) + : Stmt(IndirectGotoStmtClass), StarLoc(starLoc) { + setTarget(target); + setGotoLoc(gotoLoc); + } /// Build an empty indirect goto statement. explicit IndirectGotoStmt(EmptyShell Empty) : Stmt(IndirectGotoStmtClass, Empty) {} - void setGotoLoc(SourceLocation L) { GotoLoc = L; } - SourceLocation getGotoLoc() const { return GotoLoc; } + void setGotoLoc(SourceLocation L) { GotoStmtBits.GotoLoc = L; } + SourceLocation getGotoLoc() const { return GotoStmtBits.GotoLoc; } void setStarLoc(SourceLocation L) { StarLoc = L; } SourceLocation getStarLoc() const { return StarLoc; } - Expr *getTarget() { return reinterpret_cast<Expr*>(Target); } - const Expr *getTarget() const {return reinterpret_cast<const Expr*>(Target);} - void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); } + Expr *getTarget() { return reinterpret_cast<Expr *>(Target); } + const Expr *getTarget() const { + return reinterpret_cast<const Expr *>(Target); + } + void setTarget(Expr *E) { Target = reinterpret_cast<Stmt *>(E); } /// getConstantTarget - Returns the fixed target of this indirect /// goto, if one exists. LabelDecl *getConstantTarget(); const LabelDecl *getConstantTarget() const { - return const_cast<IndirectGotoStmt*>(this)->getConstantTarget(); + return const_cast<IndirectGotoStmt *>(this)->getConstantTarget(); } - SourceLocation getLocStart() const LLVM_READONLY { return GotoLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Target->getLocEnd(); } + SourceLocation getBeginLoc() const { return getGotoLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { return Target->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == IndirectGotoStmtClass; } // Iterators - child_range children() { return child_range(&Target, &Target+1); } + child_range children() { return child_range(&Target, &Target + 1); } }; /// ContinueStmt - This represents a continue. class ContinueStmt : public Stmt { - SourceLocation ContinueLoc; - public: - ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass), ContinueLoc(CL) {} + ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass) { + setContinueLoc(CL); + } /// Build an empty continue statement. explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) {} - SourceLocation getContinueLoc() const { return ContinueLoc; } - void setContinueLoc(SourceLocation L) { ContinueLoc = L; } + SourceLocation getContinueLoc() const { return ContinueStmtBits.ContinueLoc; } + void setContinueLoc(SourceLocation L) { ContinueStmtBits.ContinueLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return ContinueLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return ContinueLoc; } + SourceLocation getBeginLoc() const { return getContinueLoc(); } + SourceLocation getEndLoc() const { return getContinueLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ContinueStmtClass; @@ -1397,22 +2408,19 @@ public: /// BreakStmt - This represents a break. class BreakStmt : public Stmt { - SourceLocation BreakLoc; - public: - BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) { - static_assert(sizeof(BreakStmt) == 2 * sizeof(SourceLocation), - "BreakStmt too large"); + BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass) { + setBreakLoc(BL); } /// Build an empty break statement. explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) {} - SourceLocation getBreakLoc() const { return BreakLoc; } - void setBreakLoc(SourceLocation L) { BreakLoc = L; } + SourceLocation getBreakLoc() const { return BreakStmtBits.BreakLoc; } + void setBreakLoc(SourceLocation L) { BreakStmtBits.BreakLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return BreakLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return BreakLoc; } + SourceLocation getBeginLoc() const { return getBreakLoc(); } + SourceLocation getEndLoc() const { return getBreakLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == BreakStmtClass; @@ -1432,40 +2440,68 @@ public: /// return a value, and it allows returning a value in functions declared to /// return void. We explicitly model this in the AST, which means you can't /// depend on the return type of the function and the presence of an argument. -class ReturnStmt : public Stmt { - SourceLocation RetLoc; +class ReturnStmt final + : public Stmt, + private llvm::TrailingObjects<ReturnStmt, const VarDecl *> { + friend TrailingObjects; + + /// The return expression. Stmt *RetExpr; - const VarDecl *NRVOCandidate; -public: - explicit ReturnStmt(SourceLocation RL) : ReturnStmt(RL, nullptr, nullptr) {} + // ReturnStmt is followed optionally by a trailing "const VarDecl *" + // for the NRVO candidate. Present if and only if hasNRVOCandidate(). + + /// True if this ReturnStmt has storage for an NRVO candidate. + bool hasNRVOCandidate() const { return ReturnStmtBits.HasNRVOCandidate; } - ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate) - : Stmt(ReturnStmtClass), RetLoc(RL), RetExpr((Stmt *)E), - NRVOCandidate(NRVOCandidate) {} + unsigned numTrailingObjects(OverloadToken<const VarDecl *>) const { + return hasNRVOCandidate(); + } - /// Build an empty return expression. - explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) {} + /// Build a return statement. + ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate); - const Expr *getRetValue() const; - Expr *getRetValue(); - void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt*>(E); } + /// Build an empty return statement. + explicit ReturnStmt(EmptyShell Empty, bool HasNRVOCandidate); + +public: + /// Create a return statement. + static ReturnStmt *Create(const ASTContext &Ctx, SourceLocation RL, Expr *E, + const VarDecl *NRVOCandidate); - SourceLocation getReturnLoc() const { return RetLoc; } - void setReturnLoc(SourceLocation L) { RetLoc = L; } + /// Create an empty return statement, optionally with + /// storage for an NRVO candidate. + static ReturnStmt *CreateEmpty(const ASTContext &Ctx, bool HasNRVOCandidate); + + Expr *getRetValue() { return reinterpret_cast<Expr *>(RetExpr); } + const Expr *getRetValue() const { return reinterpret_cast<Expr *>(RetExpr); } + void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt *>(E); } /// Retrieve the variable that might be used for the named return /// value optimization. /// /// The optimization itself can only be performed if the variable is /// also marked as an NRVO object. - const VarDecl *getNRVOCandidate() const { return NRVOCandidate; } - void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; } + const VarDecl *getNRVOCandidate() const { + return hasNRVOCandidate() ? *getTrailingObjects<const VarDecl *>() + : nullptr; + } + + /// Set the variable that might be used for the named return value + /// optimization. The return statement must have storage for it, + /// which is the case if and only if hasNRVOCandidate() is true. + void setNRVOCandidate(const VarDecl *Var) { + assert(hasNRVOCandidate() && + "This return statement has no storage for an NRVO candidate!"); + *getTrailingObjects<const VarDecl *>() = Var; + } - SourceLocation getLocStart() const LLVM_READONLY { return RetLoc; } + SourceLocation getReturnLoc() const { return ReturnStmtBits.RetLoc; } + void setReturnLoc(SourceLocation L) { ReturnStmtBits.RetLoc = L; } - SourceLocation getLocEnd() const LLVM_READONLY { - return RetExpr ? RetExpr->getLocEnd() : RetLoc; + SourceLocation getBeginLoc() const { return getReturnLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { + return RetExpr ? RetExpr->getEndLoc() : getReturnLoc(); } static bool classof(const Stmt *T) { @@ -1474,7 +2510,8 @@ public: // Iterators child_range children() { - if (RetExpr) return child_range(&RetExpr, &RetExpr+1); + if (RetExpr) + return child_range(&RetExpr, &RetExpr + 1); return child_range(child_iterator(), child_iterator()); } }; @@ -1519,8 +2556,8 @@ public: bool isVolatile() const { return IsVolatile; } void setVolatile(bool V) { IsVolatile = V; } - SourceLocation getLocStart() const LLVM_READONLY { return {}; } - SourceLocation getLocEnd() const LLVM_READONLY { return {}; } + SourceLocation getBeginLoc() const LLVM_READONLY { return {}; } + SourceLocation getEndLoc() const LLVM_READONLY { return {}; } //===--- Asm String Analysis ---===// @@ -1801,8 +2838,8 @@ public: return Clobbers[i]; } - SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return AsmLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == GCCAsmStmtClass; @@ -1899,8 +2936,7 @@ private: ArrayRef<Expr*> Exprs, ArrayRef<StringRef> Clobbers); public: - SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return AsmLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == MSAsmStmtClass; @@ -1929,11 +2965,10 @@ public: Expr *FilterExpr, Stmt *Block); - SourceLocation getLocStart() const LLVM_READONLY { return getExceptLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return getExceptLoc(); } SourceLocation getExceptLoc() const { return Loc; } - SourceLocation getEndLoc() const { return getBlock()->getLocEnd(); } + SourceLocation getEndLoc() const { return getBlock()->getEndLoc(); } Expr *getFilterExpr() const { return reinterpret_cast<Expr*>(Children[FILTER_EXPR]); @@ -1967,11 +3002,10 @@ public: SourceLocation FinallyLoc, Stmt *Block); - SourceLocation getLocStart() const LLVM_READONLY { return getFinallyLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return getFinallyLoc(); } SourceLocation getFinallyLoc() const { return Loc; } - SourceLocation getEndLoc() const { return Block->getLocEnd(); } + SourceLocation getEndLoc() const { return Block->getEndLoc(); } CompoundStmt *getBlock() const { return cast<CompoundStmt>(Block); } @@ -2006,11 +3040,10 @@ public: SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler); - SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return getTryLoc(); } SourceLocation getTryLoc() const { return TryLoc; } - SourceLocation getEndLoc() const { return Children[HANDLER]->getLocEnd(); } + SourceLocation getEndLoc() const { return Children[HANDLER]->getEndLoc(); } bool getIsCXXTry() const { return IsCXXTry; } @@ -2047,8 +3080,8 @@ public: SourceLocation getLeaveLoc() const { return LeaveLoc; } void setLeaveLoc(SourceLocation L) { LeaveLoc = L; } - SourceLocation getLocStart() const LLVM_READONLY { return LeaveLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return LeaveLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { return LeaveLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return LeaveLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == SEHLeaveStmtClass; @@ -2261,12 +3294,12 @@ public: return capture_init_begin() + NumCaptures; } - SourceLocation getLocStart() const LLVM_READONLY { - return getCapturedStmt()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getCapturedStmt()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return getCapturedStmt()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getCapturedStmt()->getEndLoc(); } SourceRange getSourceRange() const LLVM_READONLY { diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index 34553741eb38..d3a3cf783c66 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -41,9 +41,9 @@ public: CXXCatchStmt(EmptyShell Empty) : Stmt(CXXCatchStmtClass), ExceptionDecl(nullptr), HandlerBlock(nullptr) {} - SourceLocation getLocStart() const LLVM_READONLY { return CatchLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return HandlerBlock->getLocEnd(); + SourceLocation getBeginLoc() const LLVM_READONLY { return CatchLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return HandlerBlock->getEndLoc(); } SourceLocation getCatchLoc() const { return CatchLoc; } @@ -86,12 +86,11 @@ public: static CXXTryStmt *Create(const ASTContext &C, EmptyShell Empty, unsigned numHandlers); - SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return getTryLoc(); } SourceLocation getTryLoc() const { return TryLoc; } SourceLocation getEndLoc() const { - return getStmts()[NumHandlers]->getLocEnd(); + return getStmts()[NumHandlers]->getEndLoc(); } CompoundStmt *getTryBlock() { @@ -119,14 +118,15 @@ public: }; /// CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for -/// statement, represented as 'for (range-declarator : range-expression)'. +/// statement, represented as 'for (range-declarator : range-expression)' +/// or 'for (init-statement range-declarator : range-expression)'. /// /// This is stored in a partially-desugared form to allow full semantic /// analysis of the constituent components. The original syntactic components /// can be extracted using getLoopVariable and getRangeInit. class CXXForRangeStmt : public Stmt { SourceLocation ForLoc; - enum { RANGE, BEGINSTMT, ENDSTMT, COND, INC, LOOPVAR, BODY, END }; + enum { INIT, RANGE, BEGINSTMT, ENDSTMT, COND, INC, LOOPVAR, BODY, END }; // SubExprs[RANGE] is an expression or declstmt. // SubExprs[COND] and SubExprs[INC] are expressions. Stmt *SubExprs[END]; @@ -136,16 +136,17 @@ class CXXForRangeStmt : public Stmt { friend class ASTStmtReader; public: - CXXForRangeStmt(DeclStmt *Range, DeclStmt *Begin, DeclStmt *End, - Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body, - SourceLocation FL, SourceLocation CAL, SourceLocation CL, - SourceLocation RPL); + CXXForRangeStmt(Stmt *InitStmt, DeclStmt *Range, DeclStmt *Begin, + DeclStmt *End, Expr *Cond, Expr *Inc, DeclStmt *LoopVar, + Stmt *Body, SourceLocation FL, SourceLocation CAL, + SourceLocation CL, SourceLocation RPL); CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { } - + Stmt *getInit() { return SubExprs[INIT]; } VarDecl *getLoopVariable(); Expr *getRangeInit(); + const Stmt *getInit() const { return SubExprs[INIT]; } const VarDecl *getLoopVariable() const; const Expr *getRangeInit() const; @@ -180,6 +181,7 @@ public: } const Stmt *getBody() const { return SubExprs[BODY]; } + void setInit(Stmt *S) { SubExprs[INIT] = S; } void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); } void setRangeStmt(Stmt *S) { SubExprs[RANGE] = S; } void setBeginStmt(Stmt *S) { SubExprs[BEGINSTMT] = S; } @@ -194,9 +196,9 @@ public: SourceLocation getColonLoc() const { return ColonLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } - SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return SubExprs[BODY]->getLocEnd(); + SourceLocation getBeginLoc() const LLVM_READONLY { return ForLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return SubExprs[BODY]->getEndLoc(); } static bool classof(const Stmt *T) { @@ -280,8 +282,10 @@ public: return reinterpret_cast<CompoundStmt *>(SubStmt); } - SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return SubStmt->getEndLoc(); + } child_range children() { return child_range(&SubStmt, &SubStmt+1); @@ -399,12 +403,12 @@ public: return {getStoredStmts() + SubStmt::FirstParamMove, NumParams}; } - SourceLocation getLocStart() const LLVM_READONLY { - return getBody() ? getBody()->getLocStart() - : getPromiseDecl()->getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { + return getBody() ? getBody()->getBeginLoc() + : getPromiseDecl()->getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { - return getBody() ? getBody()->getLocEnd() : getPromiseDecl()->getLocEnd(); + SourceLocation getEndLoc() const LLVM_READONLY { + return getBody() ? getBody()->getEndLoc() : getPromiseDecl()->getEndLoc(); } child_range children() { @@ -464,9 +468,9 @@ public: bool isImplicit() const { return IsImplicit; } void setIsImplicit(bool value = true) { IsImplicit = value; } - SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return getOperand() ? getOperand()->getLocEnd() : getLocStart(); + SourceLocation getBeginLoc() const LLVM_READONLY { return CoreturnLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return getOperand() ? getOperand()->getEndLoc() : getBeginLoc(); } child_range children() { diff --git a/include/clang/AST/StmtDataCollectors.td b/include/clang/AST/StmtDataCollectors.td index bf5f8c21707f..90ca08027330 100644 --- a/include/clang/AST/StmtDataCollectors.td +++ b/include/clang/AST/StmtDataCollectors.td @@ -3,8 +3,8 @@ class Stmt { addData(S->getStmtClass()); // This ensures that non-macro-generated code isn't identical to // macro-generated code. - addData(data_collection::getMacroStack(S->getLocStart(), Context)); - addData(data_collection::getMacroStack(S->getLocEnd(), Context)); + addData(data_collection::getMacroStack(S->getBeginLoc(), Context)); + addData(data_collection::getMacroStack(S->getEndLoc(), Context)); }]; } @@ -27,7 +27,7 @@ class ExpressionTraitExpr { } class PredefinedExpr { code Code = [{ - addData(S->getIdentType()); + addData(S->getIdentKind()); }]; } class TypeTraitExpr { diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h index 0b2cc78b65be..f0c0a9aeb6ac 100644 --- a/include/clang/AST/StmtObjC.h +++ b/include/clang/AST/StmtObjC.h @@ -55,9 +55,9 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } - SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return SubExprs[BODY]->getLocEnd(); + SourceLocation getBeginLoc() const LLVM_READONLY { return ForLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return SubExprs[BODY]->getEndLoc(); } static bool classof(const Stmt *T) { @@ -104,8 +104,8 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } - SourceLocation getLocStart() const LLVM_READONLY { return AtCatchLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return Body->getLocEnd(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return AtCatchLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return Body->getEndLoc(); } bool hasEllipsis() const { return getCatchParamDecl() == nullptr; } @@ -133,9 +133,9 @@ public: Stmt *getFinallyBody() { return AtFinallyStmt; } void setFinallyBody(Stmt *S) { AtFinallyStmt = S; } - SourceLocation getLocStart() const LLVM_READONLY { return AtFinallyLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return AtFinallyStmt->getLocEnd(); + SourceLocation getBeginLoc() const LLVM_READONLY { return AtFinallyLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return AtFinallyStmt->getEndLoc(); } SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; } @@ -238,8 +238,8 @@ public: getStmts()[1 + NumCatchStmts] = S; } - SourceLocation getLocStart() const LLVM_READONLY { return AtTryLoc; } - SourceLocation getLocEnd() const LLVM_READONLY; + SourceLocation getBeginLoc() const LLVM_READONLY { return AtTryLoc; } + SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCAtTryStmtClass; @@ -295,9 +295,9 @@ public: } void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; } - SourceLocation getLocStart() const LLVM_READONLY { return AtSynchronizedLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return getSynchBody()->getLocEnd(); + SourceLocation getBeginLoc() const LLVM_READONLY { return AtSynchronizedLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return getSynchBody()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -329,9 +329,9 @@ public: SourceLocation getThrowLoc() const LLVM_READONLY { return AtThrowLoc; } void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; } - SourceLocation getLocStart() const LLVM_READONLY { return AtThrowLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { - return Throw ? Throw->getLocEnd() : AtThrowLoc; + SourceLocation getBeginLoc() const LLVM_READONLY { return AtThrowLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return Throw ? Throw->getEndLoc() : AtThrowLoc; } static bool classof(const Stmt *T) { @@ -357,8 +357,10 @@ public: Stmt *getSubStmt() { return SubStmt; } void setSubStmt(Stmt *S) { SubStmt = S; } - SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();} + SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return SubStmt->getEndLoc(); + } SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h index d23375e7606b..d1eedd62b372 100644 --- a/include/clang/AST/StmtOpenMP.h +++ b/include/clang/AST/StmtOpenMP.h @@ -165,9 +165,9 @@ public: } /// Returns starting location of directive kind. - SourceLocation getLocStart() const { return StartLoc; } + SourceLocation getBeginLoc() const { return StartLoc; } /// Returns ending location of directive. - SourceLocation getLocEnd() const { return EndLoc; } + SourceLocation getEndLoc() const { return EndLoc; } /// Set starting location of directive kind. /// @@ -392,9 +392,11 @@ class OMPLoopDirective : public OMPExecutableDirective { CombinedConditionOffset = 25, CombinedNextLowerBoundOffset = 26, CombinedNextUpperBoundOffset = 27, + CombinedDistConditionOffset = 28, + CombinedParForInDistConditionOffset = 29, // Offset to the end (and start of the following counters/updates/finals // arrays) for combined distribute loop directives. - CombinedDistributeEnd = 28, + CombinedDistributeEnd = 30, }; /// Get the counters storage. @@ -605,6 +607,17 @@ protected: "expected loop bound sharing directive"); *std::next(child_begin(), CombinedNextUpperBoundOffset) = CombNUB; } + void setCombinedDistCond(Expr *CombDistCond) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound distribute sharing directive"); + *std::next(child_begin(), CombinedDistConditionOffset) = CombDistCond; + } + void setCombinedParForInDistCond(Expr *CombParForInDistCond) { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound distribute sharing directive"); + *std::next(child_begin(), + CombinedParForInDistConditionOffset) = CombParForInDistCond; + } void setCounters(ArrayRef<Expr *> A); void setPrivateCounters(ArrayRef<Expr *> A); void setInits(ArrayRef<Expr *> A); @@ -637,6 +650,13 @@ public: /// Update of UpperBound for statically scheduled omp loops for /// outer loop in combined constructs (e.g. 'distribute parallel for') Expr *NUB; + /// Distribute Loop condition used when composing 'omp distribute' + /// with 'omp for' in a same construct when schedule is chunked. + Expr *DistCond; + /// 'omp parallel for' loop condition used when composed with + /// 'omp distribute' in the same construct and when schedule is + /// chunked and the chunk size is 1. + Expr *ParForInDistCond; }; /// The expressions built for the OpenMP loop CodeGen for the @@ -754,6 +774,8 @@ public: DistCombinedFields.Cond = nullptr; DistCombinedFields.NLB = nullptr; DistCombinedFields.NUB = nullptr; + DistCombinedFields.DistCond = nullptr; + DistCombinedFields.ParForInDistCond = nullptr; } }; @@ -922,6 +944,18 @@ public: return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), CombinedNextUpperBoundOffset))); } + Expr *getCombinedDistCond() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound distribute sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedDistConditionOffset))); + } + Expr *getCombinedParForInDistCond() const { + assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) && + "expected loop bound distribute sharing directive"); + return const_cast<Expr *>(reinterpret_cast<const Expr *>( + *std::next(child_begin(), CombinedParForInDistConditionOffset))); + } const Stmt *getBody() const { // This relies on the loop form is already checked by Sema. const Stmt *Body = diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h index 30bc257c7e79..ea40e0497307 100644 --- a/include/clang/AST/StmtVisitor.h +++ b/include/clang/AST/StmtVisitor.h @@ -22,15 +22,12 @@ #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include <utility> namespace clang { - -template <typename T> struct make_ptr { using type = T *; }; -template <typename T> struct make_const_ptr { using type = const T *; }; - /// StmtVisitorBase - This class implements a simple visitor for Stmt /// subclasses. Since Expr derives from Stmt, this also includes support for /// visiting Exprs. @@ -182,53 +179,19 @@ public: /// /// This class does not preserve constness of Stmt pointers (see also /// ConstStmtVisitor). -template<typename ImplClass, typename RetTy=void, typename... ParamTys> +template <typename ImplClass, typename RetTy = void, typename... ParamTys> class StmtVisitor - : public StmtVisitorBase<make_ptr, ImplClass, RetTy, ParamTys...> {}; + : public StmtVisitorBase<std::add_pointer, ImplClass, RetTy, ParamTys...> { +}; /// ConstStmtVisitor - This class implements a simple visitor for Stmt /// subclasses. Since Expr derives from Stmt, this also includes support for /// visiting Exprs. /// /// This class preserves constness of Stmt pointers (see also StmtVisitor). -template<typename ImplClass, typename RetTy=void, typename... ParamTys> -class ConstStmtVisitor - : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy, ParamTys...> {}; - -/// This class implements a simple visitor for OMPClause -/// subclasses. -template<class ImplClass, template <typename> class Ptr, typename RetTy> -class OMPClauseVisitorBase { -public: -#define PTR(CLASS) typename Ptr<CLASS>::type -#define DISPATCH(CLASS) \ - return static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<PTR(CLASS)>(S)) - -#define OPENMP_CLAUSE(Name, Class) \ - RetTy Visit ## Class (PTR(Class) S) { DISPATCH(Class); } -#include "clang/Basic/OpenMPKinds.def" - - RetTy Visit(PTR(OMPClause) S) { - // Top switch clause: visit each OMPClause. - switch (S->getClauseKind()) { - default: llvm_unreachable("Unknown clause kind!"); -#define OPENMP_CLAUSE(Name, Class) \ - case OMPC_ ## Name : return Visit ## Class(static_cast<PTR(Class)>(S)); -#include "clang/Basic/OpenMPKinds.def" - } - } - // Base case, ignore it. :) - RetTy VisitOMPClause(PTR(OMPClause) Node) { return RetTy(); } -#undef PTR -#undef DISPATCH -}; - -template<class ImplClass, typename RetTy = void> -class OMPClauseVisitor : - public OMPClauseVisitorBase <ImplClass, make_ptr, RetTy> {}; -template<class ImplClass, typename RetTy = void> -class ConstOMPClauseVisitor : - public OMPClauseVisitorBase <ImplClass, make_const_ptr, RetTy> {}; +template <typename ImplClass, typename RetTy = void, typename... ParamTys> +class ConstStmtVisitor : public StmtVisitorBase<llvm::make_const_ptr, ImplClass, + RetTy, ParamTys...> {}; } // namespace clang diff --git a/include/clang/AST/TemplateArgumentVisitor.h b/include/clang/AST/TemplateArgumentVisitor.h new file mode 100644 index 000000000000..e1cc392a1705 --- /dev/null +++ b/include/clang/AST/TemplateArgumentVisitor.h @@ -0,0 +1,99 @@ +//===- TemplateArgumentVisitor.h - Visitor for TArg subclasses --*- 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 TemplateArgumentVisitor interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TEMPLATEARGUMENTVISITOR_H +#define LLVM_CLANG_AST_TEMPLATEARGUMENTVISITOR_H + +#include "clang/AST/TemplateBase.h" + +namespace clang { + +namespace templateargumentvisitor { + +/// A simple visitor class that helps create template argument visitors. +template <template <typename> class Ref, typename ImplClass, + typename RetTy = void, typename... ParamTys> +class Base { +public: +#define REF(CLASS) typename Ref<CLASS>::type +#define DISPATCH(NAME) \ + case TemplateArgument::NAME: \ + return static_cast<ImplClass *>(this)->Visit##NAME##TemplateArgument( \ + TA, std::forward<ParamTys>(P)...) + + RetTy Visit(REF(TemplateArgument) TA, ParamTys... P) { + switch (TA.getKind()) { + DISPATCH(Null); + DISPATCH(Type); + DISPATCH(Declaration); + DISPATCH(NullPtr); + DISPATCH(Integral); + DISPATCH(Template); + DISPATCH(TemplateExpansion); + DISPATCH(Expression); + DISPATCH(Pack); + } + llvm_unreachable("TemplateArgument is not covered in switch!"); + } + + // If the implementation chooses not to implement a certain visit + // method, fall back to the parent. + +#define VISIT_METHOD(CATEGORY) \ + RetTy Visit##CATEGORY##TemplateArgument(REF(TemplateArgument) TA, \ + ParamTys... P) { \ + return VisitTemplateArgument(TA, std::forward<ParamTys>(P)...); \ + } + + VISIT_METHOD(Null); + VISIT_METHOD(Type); + VISIT_METHOD(Declaration); + VISIT_METHOD(NullPtr); + VISIT_METHOD(Integral); + VISIT_METHOD(Template); + VISIT_METHOD(TemplateExpansion); + VISIT_METHOD(Expression); + VISIT_METHOD(Pack); + + RetTy VisitTemplateArgument(REF(TemplateArgument), ParamTys...) { + return RetTy(); + } + +#undef REF +#undef DISPATCH +#undef VISIT_METHOD +}; + +} // namespace templateargumentvisitor + +/// A simple visitor class that helps create template argument visitors. +/// +/// This class does not preserve constness of TemplateArgument references (see +/// also ConstTemplateArgumentVisitor). +template <typename ImplClass, typename RetTy = void, typename... ParamTys> +class TemplateArgumentVisitor + : public templateargumentvisitor::Base<std::add_lvalue_reference, ImplClass, + RetTy, ParamTys...> {}; + +/// A simple visitor class that helps create template argument visitors. +/// +/// This class preserves constness of TemplateArgument references (see also +/// TemplateArgumentVisitor). +template <typename ImplClass, typename RetTy = void, typename... ParamTys> +class ConstTemplateArgumentVisitor + : public templateargumentvisitor::Base<llvm::make_const_ref, ImplClass, + RetTy, ParamTys...> {}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_TEMPLATEARGUMENTVISITOR_H diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index 6898ef4e1b8a..e3a773b4e490 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -467,7 +467,7 @@ public: : Argument(Argument), LocInfo(E) { // Permit any kind of template argument that can be represented with an - // expression + // expression. assert(Argument.getKind() == TemplateArgument::NullPtr || Argument.getKind() == TemplateArgument::Integral || Argument.getKind() == TemplateArgument::Declaration || @@ -530,19 +530,22 @@ public: } NestedNameSpecifierLoc getTemplateQualifierLoc() const { - assert(Argument.getKind() == TemplateArgument::Template || - Argument.getKind() == TemplateArgument::TemplateExpansion); + if (Argument.getKind() != TemplateArgument::Template && + Argument.getKind() != TemplateArgument::TemplateExpansion) + return NestedNameSpecifierLoc(); return LocInfo.getTemplateQualifierLoc(); } SourceLocation getTemplateNameLoc() const { - assert(Argument.getKind() == TemplateArgument::Template || - Argument.getKind() == TemplateArgument::TemplateExpansion); + if (Argument.getKind() != TemplateArgument::Template && + Argument.getKind() != TemplateArgument::TemplateExpansion) + return SourceLocation(); return LocInfo.getTemplateNameLoc(); } SourceLocation getTemplateEllipsisLoc() const { - assert(Argument.getKind() == TemplateArgument::TemplateExpansion); + if (Argument.getKind() != TemplateArgument::TemplateExpansion) + return SourceLocation(); return LocInfo.getTemplateEllipsisLoc(); } }; @@ -617,13 +620,17 @@ public: /// The number of template arguments in TemplateArgs. unsigned NumTemplateArgs; + SourceLocation getLAngleLoc() const { return LAngleLoc; } + SourceLocation getRAngleLoc() const { return RAngleLoc; } + /// Retrieve the template arguments const TemplateArgumentLoc *getTemplateArgs() const { return getTrailingObjects<TemplateArgumentLoc>(); } + unsigned getNumTemplateArgs() const { return NumTemplateArgs; } llvm::ArrayRef<TemplateArgumentLoc> arguments() const { - return llvm::makeArrayRef(getTemplateArgs(), NumTemplateArgs); + return llvm::makeArrayRef(getTemplateArgs(), getNumTemplateArgs()); } const TemplateArgumentLoc &operator[](unsigned I) const { diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index d88d58d0a2aa..48272597d4d1 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_TEMPLATENAME_H #define LLVM_CLANG_AST_TEMPLATENAME_H +#include "clang/AST/NestedNameSpecifier.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" diff --git a/include/clang/AST/TextNodeDumper.h b/include/clang/AST/TextNodeDumper.h new file mode 100644 index 000000000000..794066376300 --- /dev/null +++ b/include/clang/AST/TextNodeDumper.h @@ -0,0 +1,298 @@ +//===--- TextNodeDumper.h - Printing of AST nodes -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements AST dumping of components of individual AST nodes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TEXTNODEDUMPER_H +#define LLVM_CLANG_AST_TEXTNODEDUMPER_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDumperUtils.h" +#include "clang/AST/AttrVisitor.h" +#include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/CommentVisitor.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TemplateArgumentVisitor.h" +#include "clang/AST/TypeVisitor.h" + +namespace clang { + +class TextTreeStructure { + raw_ostream &OS; + const bool ShowColors; + + /// Pending[i] is an action to dump an entity at level i. + llvm::SmallVector<std::function<void(bool IsLastChild)>, 32> Pending; + + /// Indicates whether we're at the top level. + bool TopLevel = true; + + /// Indicates if we're handling the first child after entering a new depth. + bool FirstChild = true; + + /// Prefix for currently-being-dumped entity. + std::string Prefix; + +public: + /// Add a child of the current node. Calls DoAddChild without arguments + template <typename Fn> void AddChild(Fn DoAddChild) { + return AddChild("", DoAddChild); + } + + /// Add a child of the current node with an optional label. + /// Calls DoAddChild without arguments. + template <typename Fn> void AddChild(StringRef Label, Fn DoAddChild) { + // If we're at the top level, there's nothing interesting to do; just + // run the dumper. + if (TopLevel) { + TopLevel = false; + DoAddChild(); + while (!Pending.empty()) { + Pending.back()(true); + Pending.pop_back(); + } + Prefix.clear(); + OS << "\n"; + TopLevel = true; + return; + } + + // We need to capture an owning-string in the lambda because the lambda + // is invoked in a deferred manner. + std::string LabelStr = Label; + auto DumpWithIndent = [this, DoAddChild, LabelStr](bool IsLastChild) { + // Print out the appropriate tree structure and work out the prefix for + // children of this node. For instance: + // + // A Prefix = "" + // |-B Prefix = "| " + // | `-C Prefix = "| " + // `-D Prefix = " " + // |-E Prefix = " | " + // `-F Prefix = " " + // G Prefix = "" + // + // Note that the first level gets no prefix. + { + OS << '\n'; + ColorScope Color(OS, ShowColors, IndentColor); + OS << Prefix << (IsLastChild ? '`' : '|') << '-'; + if (!LabelStr.empty()) + OS << LabelStr << ": "; + + this->Prefix.push_back(IsLastChild ? ' ' : '|'); + this->Prefix.push_back(' '); + } + + FirstChild = true; + unsigned Depth = Pending.size(); + + DoAddChild(); + + // If any children are left, they're the last at their nesting level. + // Dump those ones out now. + while (Depth < Pending.size()) { + Pending.back()(true); + this->Pending.pop_back(); + } + + // Restore the old prefix. + this->Prefix.resize(Prefix.size() - 2); + }; + + if (FirstChild) { + Pending.push_back(std::move(DumpWithIndent)); + } else { + Pending.back()(false); + Pending.back() = std::move(DumpWithIndent); + } + FirstChild = false; + } + + TextTreeStructure(raw_ostream &OS, bool ShowColors) + : OS(OS), ShowColors(ShowColors) {} +}; + +class TextNodeDumper + : public TextTreeStructure, + public comments::ConstCommentVisitor<TextNodeDumper, void, + const comments::FullComment *>, + public ConstAttrVisitor<TextNodeDumper>, + public ConstTemplateArgumentVisitor<TextNodeDumper>, + public ConstStmtVisitor<TextNodeDumper>, + public TypeVisitor<TextNodeDumper> { + raw_ostream &OS; + const bool ShowColors; + + /// Keep track of the last location we print out so that we can + /// print out deltas from then on out. + const char *LastLocFilename = ""; + unsigned LastLocLine = ~0U; + + const SourceManager *SM; + + /// The policy to use for printing; can be defaulted. + PrintingPolicy PrintPolicy; + + const comments::CommandTraits *Traits; + + const char *getCommandName(unsigned CommandID); + +public: + TextNodeDumper(raw_ostream &OS, bool ShowColors, const SourceManager *SM, + const PrintingPolicy &PrintPolicy, + const comments::CommandTraits *Traits); + + void Visit(const comments::Comment *C, const comments::FullComment *FC); + + void Visit(const Attr *A); + + void Visit(const TemplateArgument &TA, SourceRange R, + const Decl *From = nullptr, StringRef Label = {}); + + void Visit(const Stmt *Node); + + void Visit(const Type *T); + + void Visit(QualType T); + + void Visit(const Decl *D); + + void Visit(const CXXCtorInitializer *Init); + + void Visit(const OMPClause *C); + + void Visit(const BlockDecl::Capture &C); + + void dumpPointer(const void *Ptr); + void dumpLocation(SourceLocation Loc); + void dumpSourceRange(SourceRange R); + void dumpBareType(QualType T, bool Desugar = true); + void dumpType(QualType T); + void dumpBareDeclRef(const Decl *D); + void dumpName(const NamedDecl *ND); + void dumpAccessSpecifier(AccessSpecifier AS); + + void dumpDeclRef(const Decl *D, StringRef Label = {}); + + void visitTextComment(const comments::TextComment *C, + const comments::FullComment *); + void visitInlineCommandComment(const comments::InlineCommandComment *C, + const comments::FullComment *); + void visitHTMLStartTagComment(const comments::HTMLStartTagComment *C, + const comments::FullComment *); + void visitHTMLEndTagComment(const comments::HTMLEndTagComment *C, + const comments::FullComment *); + void visitBlockCommandComment(const comments::BlockCommandComment *C, + const comments::FullComment *); + void visitParamCommandComment(const comments::ParamCommandComment *C, + const comments::FullComment *FC); + void visitTParamCommandComment(const comments::TParamCommandComment *C, + const comments::FullComment *FC); + void visitVerbatimBlockComment(const comments::VerbatimBlockComment *C, + const comments::FullComment *); + void + visitVerbatimBlockLineComment(const comments::VerbatimBlockLineComment *C, + const comments::FullComment *); + void visitVerbatimLineComment(const comments::VerbatimLineComment *C, + const comments::FullComment *); + +// Implements Visit methods for Attrs. +#include "clang/AST/AttrTextNodeDump.inc" + + void VisitNullTemplateArgument(const TemplateArgument &TA); + void VisitTypeTemplateArgument(const TemplateArgument &TA); + void VisitDeclarationTemplateArgument(const TemplateArgument &TA); + void VisitNullPtrTemplateArgument(const TemplateArgument &TA); + void VisitIntegralTemplateArgument(const TemplateArgument &TA); + void VisitTemplateTemplateArgument(const TemplateArgument &TA); + void VisitTemplateExpansionTemplateArgument(const TemplateArgument &TA); + void VisitExpressionTemplateArgument(const TemplateArgument &TA); + void VisitPackTemplateArgument(const TemplateArgument &TA); + + void VisitIfStmt(const IfStmt *Node); + void VisitSwitchStmt(const SwitchStmt *Node); + void VisitWhileStmt(const WhileStmt *Node); + void VisitLabelStmt(const LabelStmt *Node); + void VisitGotoStmt(const GotoStmt *Node); + void VisitCaseStmt(const CaseStmt *Node); + void VisitCallExpr(const CallExpr *Node); + void VisitCastExpr(const CastExpr *Node); + void VisitImplicitCastExpr(const ImplicitCastExpr *Node); + void VisitDeclRefExpr(const DeclRefExpr *Node); + void VisitPredefinedExpr(const PredefinedExpr *Node); + void VisitCharacterLiteral(const CharacterLiteral *Node); + void VisitIntegerLiteral(const IntegerLiteral *Node); + void VisitFixedPointLiteral(const FixedPointLiteral *Node); + void VisitFloatingLiteral(const FloatingLiteral *Node); + void VisitStringLiteral(const StringLiteral *Str); + void VisitInitListExpr(const InitListExpr *ILE); + void VisitUnaryOperator(const UnaryOperator *Node); + void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node); + void VisitMemberExpr(const MemberExpr *Node); + void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node); + void VisitBinaryOperator(const BinaryOperator *Node); + void VisitCompoundAssignOperator(const CompoundAssignOperator *Node); + void VisitAddrLabelExpr(const AddrLabelExpr *Node); + void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node); + void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node); + void VisitCXXThisExpr(const CXXThisExpr *Node); + void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); + void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *Node); + void VisitCXXConstructExpr(const CXXConstructExpr *Node); + void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); + void VisitCXXNewExpr(const CXXNewExpr *Node); + void VisitCXXDeleteExpr(const CXXDeleteExpr *Node); + void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node); + void VisitExprWithCleanups(const ExprWithCleanups *Node); + void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node); + void VisitSizeOfPackExpr(const SizeOfPackExpr *Node); + void + VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *Node); + void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); + void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node); + void VisitObjCMessageExpr(const ObjCMessageExpr *Node); + void VisitObjCBoxedExpr(const ObjCBoxedExpr *Node); + void VisitObjCSelectorExpr(const ObjCSelectorExpr *Node); + void VisitObjCProtocolExpr(const ObjCProtocolExpr *Node); + void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node); + void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node); + void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node); + void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node); + + void VisitRValueReferenceType(const ReferenceType *T); + void VisitArrayType(const ArrayType *T); + void VisitConstantArrayType(const ConstantArrayType *T); + void VisitVariableArrayType(const VariableArrayType *T); + void VisitDependentSizedArrayType(const DependentSizedArrayType *T); + void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T); + void VisitVectorType(const VectorType *T); + void VisitFunctionType(const FunctionType *T); + void VisitFunctionProtoType(const FunctionProtoType *T); + void VisitUnresolvedUsingType(const UnresolvedUsingType *T); + void VisitTypedefType(const TypedefType *T); + void VisitUnaryTransformType(const UnaryTransformType *T); + void VisitTagType(const TagType *T); + void VisitTemplateTypeParmType(const TemplateTypeParmType *T); + void VisitAutoType(const AutoType *T); + void VisitTemplateSpecializationType(const TemplateSpecializationType *T); + void VisitInjectedClassNameType(const InjectedClassNameType *T); + void VisitObjCInterfaceType(const ObjCInterfaceType *T); + void VisitPackExpansionType(const PackExpansionType *T); + +private: + void dumpCXXTemporary(const CXXTemporary *Temporary); +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_TEXTNODEDUMPER_H diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 9a8dd6faff31..d4c97b1b5efc 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -21,6 +21,7 @@ #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/AttrKinds.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/LLVM.h" @@ -45,6 +46,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include "llvm/Support/type_traits.h" +#include "llvm/Support/TrailingObjects.h" #include <cassert> #include <cstddef> #include <cstdint> @@ -100,48 +102,33 @@ namespace llvm { namespace clang { -class ArrayType; class ASTContext; -class AttributedType; -class AutoType; -class BuiltinType; template <typename> class CanQual; -class ComplexType; class CXXRecordDecl; class DeclContext; -class DeducedType; class EnumDecl; class Expr; class ExtQualsTypeCommonBase; class FunctionDecl; -class FunctionNoProtoType; -class FunctionProtoType; class IdentifierInfo; -class InjectedClassNameType; class NamedDecl; class ObjCInterfaceDecl; -class ObjCObjectPointerType; -class ObjCObjectType; class ObjCProtocolDecl; class ObjCTypeParamDecl; -class ParenType; struct PrintingPolicy; class RecordDecl; -class RecordType; class Stmt; class TagDecl; class TemplateArgument; class TemplateArgumentListInfo; class TemplateArgumentLoc; -class TemplateSpecializationType; class TemplateTypeParmDecl; class TypedefNameDecl; -class TypedefType; class UnresolvedUsingTypenameDecl; using CanQualType = CanQual<Type>; - // Provide forward declarations for all of the *Type classes +// Provide forward declarations for all of the *Type classes. #define TYPE(Class, Base) class Class##Type; #include "clang/AST/TypeNodes.def" @@ -269,28 +256,24 @@ public: } bool hasConst() const { return Mask & Const; } - void setConst(bool flag) { - Mask = (Mask & ~Const) | (flag ? Const : 0); - } + bool hasOnlyConst() const { return Mask == Const; } void removeConst() { Mask &= ~Const; } void addConst() { Mask |= Const; } bool hasVolatile() const { return Mask & Volatile; } - void setVolatile(bool flag) { - Mask = (Mask & ~Volatile) | (flag ? Volatile : 0); - } + bool hasOnlyVolatile() const { return Mask == Volatile; } void removeVolatile() { Mask &= ~Volatile; } void addVolatile() { Mask |= Volatile; } bool hasRestrict() const { return Mask & Restrict; } - void setRestrict(bool flag) { - Mask = (Mask & ~Restrict) | (flag ? Restrict : 0); - } + bool hasOnlyRestrict() const { return Mask == Restrict; } void removeRestrict() { Mask &= ~Restrict; } void addRestrict() { Mask |= Restrict; } bool hasCVRQualifiers() const { return getCVRQualifiers(); } unsigned getCVRQualifiers() const { return Mask & CVRMask; } + unsigned getCVRUQualifiers() const { return Mask & (CVRMask | UMask); } + void setCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask = (Mask & ~CVRMask) | mask; @@ -997,9 +980,7 @@ public: void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder = Twine(), - unsigned Indentation = 0) const { - print(split(), OS, Policy, PlaceHolder, Indentation); - } + unsigned Indentation = 0) const; static void print(SplitQualType split, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, @@ -1013,9 +994,7 @@ public: unsigned Indentation = 0); void getAsStringInternal(std::string &Str, - const PrintingPolicy &Policy) const { - return getAsStringInternal(split(), Str, Policy); - } + const PrintingPolicy &Policy) const; static void getAsStringInternal(SplitQualType split, std::string &out, const PrintingPolicy &policy) { @@ -1515,6 +1494,9 @@ protected: unsigned Kind : 8; }; + /// FunctionTypeBitfields store various bits belonging to FunctionProtoType. + /// Only common bits are stored here. Additional uncommon bits are stored + /// in a trailing object after FunctionProtoType. class FunctionTypeBitfields { friend class FunctionProtoType; friend class FunctionType; @@ -1525,18 +1507,38 @@ protected: /// regparm and the calling convention. unsigned ExtInfo : 12; + /// The ref-qualifier associated with a \c FunctionProtoType. + /// + /// This is a value of type \c RefQualifierKind. + unsigned RefQualifier : 2; + /// Used only by FunctionProtoType, put here to pack with the /// other bitfields. /// The qualifiers are part of FunctionProtoType because... /// /// C++ 8.3.5p4: The return type, the parameter type list and the /// cv-qualifier-seq, [...], are part of the function type. - unsigned TypeQuals : 4; + unsigned FastTypeQuals : Qualifiers::FastWidth; + /// Whether this function has extended Qualifiers. + unsigned HasExtQuals : 1; - /// The ref-qualifier associated with a \c FunctionProtoType. - /// - /// This is a value of type \c RefQualifierKind. - unsigned RefQualifier : 2; + /// The number of parameters this function has, not counting '...'. + /// According to [implimits] 8 bits should be enough here but this is + /// somewhat easy to exceed with metaprogramming and so we would like to + /// keep NumParams as wide as reasonably possible. + unsigned NumParams : 16; + + /// The type of exception specification this function has. + unsigned ExceptionSpecType : 4; + + /// Whether this function has extended parameter information. + unsigned HasExtParameterInfos : 1; + + /// Whether the function is variadic. + unsigned Variadic : 1; + + /// Whether this function has a trailing return type. + unsigned HasTrailingReturn : 1; }; class ObjCObjectTypeBitfields { @@ -1554,8 +1556,6 @@ protected: unsigned IsKindOf : 1; }; - static_assert(NumTypeBits + 7 + 6 + 1 <= 32, "Does not fit in an unsigned"); - class ReferenceTypeBitfields { friend class ReferenceType; @@ -1588,6 +1588,18 @@ protected: unsigned Keyword : 8; }; + enum { NumTypeWithKeywordBits = 8 }; + + class ElaboratedTypeBitfields { + friend class ElaboratedType; + + unsigned : NumTypeBits; + unsigned : NumTypeWithKeywordBits; + + /// Whether the ElaboratedType has a trailing OwnedTagDecl. + unsigned HasOwnedTagDecl : 1; + }; + class VectorTypeBitfields { friend class VectorType; friend class DependentVectorType; @@ -1623,6 +1635,74 @@ protected: unsigned Keyword : 2; }; + class SubstTemplateTypeParmPackTypeBitfields { + friend class SubstTemplateTypeParmPackType; + + unsigned : NumTypeBits; + + /// The number of template arguments in \c Arguments, which is + /// expected to be able to hold at least 1024 according to [implimits]. + /// However as this limit is somewhat easy to hit with template + /// metaprogramming we'd prefer to keep it as large as possible. + /// At the moment it has been left as a non-bitfield since this type + /// safely fits in 64 bits as an unsigned, so there is no reason to + /// introduce the performance impact of a bitfield. + unsigned NumArgs; + }; + + class TemplateSpecializationTypeBitfields { + friend class TemplateSpecializationType; + + unsigned : NumTypeBits; + + /// Whether this template specialization type is a substituted type alias. + unsigned TypeAlias : 1; + + /// The number of template arguments named in this class template + /// specialization, which is expected to be able to hold at least 1024 + /// according to [implimits]. However, as this limit is somewhat easy to + /// hit with template metaprogramming we'd prefer to keep it as large + /// as possible. At the moment it has been left as a non-bitfield since + /// this type safely fits in 64 bits as an unsigned, so there is no reason + /// to introduce the performance impact of a bitfield. + unsigned NumArgs; + }; + + class DependentTemplateSpecializationTypeBitfields { + friend class DependentTemplateSpecializationType; + + unsigned : NumTypeBits; + unsigned : NumTypeWithKeywordBits; + + /// The number of template arguments named in this class template + /// specialization, which is expected to be able to hold at least 1024 + /// according to [implimits]. However, as this limit is somewhat easy to + /// hit with template metaprogramming we'd prefer to keep it as large + /// as possible. At the moment it has been left as a non-bitfield since + /// this type safely fits in 64 bits as an unsigned, so there is no reason + /// to introduce the performance impact of a bitfield. + unsigned NumArgs; + }; + + class PackExpansionTypeBitfields { + friend class PackExpansionType; + + unsigned : NumTypeBits; + + /// The number of expansions that this pack expansion will + /// generate when substituted (+1), which is expected to be able to + /// hold at least 1024 according to [implimits]. However, as this limit + /// is somewhat easy to hit with template metaprogramming we'd prefer to + /// keep it as large as possible. At the moment it has been left as a + /// non-bitfield since this type safely fits in 64 bits as an unsigned, so + /// there is no reason to introduce the performance impact of a bitfield. + /// + /// This field will only have a non-zero value when some of the parameter + /// packs that occur within the pattern have been substituted but others + /// have not. + unsigned NumExpansions; + }; + union { TypeBitfields TypeBits; ArrayTypeBitfields ArrayTypeBits; @@ -1633,7 +1713,47 @@ protected: ObjCObjectTypeBitfields ObjCObjectTypeBits; ReferenceTypeBitfields ReferenceTypeBits; TypeWithKeywordBitfields TypeWithKeywordBits; + ElaboratedTypeBitfields ElaboratedTypeBits; VectorTypeBitfields VectorTypeBits; + SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits; + TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits; + DependentTemplateSpecializationTypeBitfields + DependentTemplateSpecializationTypeBits; + PackExpansionTypeBitfields PackExpansionTypeBits; + + static_assert(sizeof(TypeBitfields) <= 8, + "TypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(ArrayTypeBitfields) <= 8, + "ArrayTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(AttributedTypeBitfields) <= 8, + "AttributedTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(AutoTypeBitfields) <= 8, + "AutoTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(BuiltinTypeBitfields) <= 8, + "BuiltinTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(FunctionTypeBitfields) <= 8, + "FunctionTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(ObjCObjectTypeBitfields) <= 8, + "ObjCObjectTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(ReferenceTypeBitfields) <= 8, + "ReferenceTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(TypeWithKeywordBitfields) <= 8, + "TypeWithKeywordBitfields is larger than 8 bytes!"); + static_assert(sizeof(ElaboratedTypeBitfields) <= 8, + "ElaboratedTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(VectorTypeBitfields) <= 8, + "VectorTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(SubstTemplateTypeParmPackTypeBitfields) <= 8, + "SubstTemplateTypeParmPackTypeBitfields is larger" + " than 8 bytes!"); + static_assert(sizeof(TemplateSpecializationTypeBitfields) <= 8, + "TemplateSpecializationTypeBitfields is larger" + " than 8 bytes!"); + static_assert(sizeof(DependentTemplateSpecializationTypeBitfields) <= 8, + "DependentTemplateSpecializationTypeBitfields is larger" + " than 8 bytes!"); + static_assert(sizeof(PackExpansionTypeBitfields) <= 8, + "PackExpansionTypeBitfields is larger than 8 bytes"); }; private: @@ -1866,7 +1986,16 @@ public: bool isObjCQualifiedClassType() const; // Class<foo> bool isObjCObjectOrInterfaceType() const; bool isObjCIdType() const; // id - bool isObjCInertUnsafeUnretainedType() const; + + /// Was this type written with the special inert-in-ARC __unsafe_unretained + /// qualifier? + /// + /// This approximates the answer to the following question: if this + /// translation unit were compiled in ARC, would this type be qualified + /// with __unsafe_unretained? + bool isObjCInertUnsafeUnretainedType() const { + return hasAttr(attr::ObjCInertUnsafeUnretained); + } /// Whether the type is Objective-C 'id' or a __kindof type of an /// object type, e.g., __kindof NSView * or __kindof id @@ -1911,6 +2040,13 @@ public: bool isQueueT() const; // OpenCL queue_t bool isReserveIDT() const; // OpenCL reserve_id_t +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ + bool is##Id##Type() const; +#include "clang/Basic/OpenCLExtensionTypes.def" + // Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension + bool isOCLIntelSubgroupAVCType() const; + bool isOCLExtOpaqueType() const; // Any OpenCL extension type + bool isPipeType() const; // OpenCL pipe type bool isOpenCLSpecificType() const; // Any OpenCL specific type @@ -1931,7 +2067,8 @@ public: STK_Integral, STK_Floating, STK_IntegralComplex, - STK_FloatingComplex + STK_FloatingComplex, + STK_FixedPoint }; /// Given that this is a scalar type, classify it. @@ -2080,6 +2217,10 @@ public: /// qualifiers from the outermost type. const ArrayType *castAsArrayTypeUnsafe() const; + /// Determine whether this type had the specified attribute applied to it + /// (looking through top-level type sugar). + bool hasAttr(attr::Kind AK) const; + /// Get the base element type of this type, potentially discarding type /// qualifiers. This should never be used when type qualifiers /// are meaningful. @@ -2253,6 +2394,9 @@ public: // OpenCL image types #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) Id, #include "clang/Basic/OpenCLImageTypes.def" +// OpenCL extension types +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id, +#include "clang/Basic/OpenCLExtensionTypes.def" // All other builtin types #define BUILTIN_TYPE(Id, SingletonId) Id, #define LAST_BUILTIN_TYPE(Id) LastKind = Id @@ -3213,6 +3357,92 @@ class FunctionType : public Type { QualType ResultType; public: + /// Interesting information about a specific parameter that can't simply + /// be reflected in parameter's type. This is only used by FunctionProtoType + /// but is in FunctionType to make this class available during the + /// specification of the bases of FunctionProtoType. + /// + /// It makes sense to model language features this way when there's some + /// sort of parameter-specific override (such as an attribute) that + /// affects how the function is called. For example, the ARC ns_consumed + /// attribute changes whether a parameter is passed at +0 (the default) + /// or +1 (ns_consumed). This must be reflected in the function type, + /// but isn't really a change to the parameter type. + /// + /// One serious disadvantage of modelling language features this way is + /// that they generally do not work with language features that attempt + /// to destructure types. For example, template argument deduction will + /// not be able to match a parameter declared as + /// T (*)(U) + /// against an argument of type + /// void (*)(__attribute__((ns_consumed)) id) + /// because the substitution of T=void, U=id into the former will + /// not produce the latter. + class ExtParameterInfo { + enum { + ABIMask = 0x0F, + IsConsumed = 0x10, + HasPassObjSize = 0x20, + IsNoEscape = 0x40, + }; + unsigned char Data = 0; + + public: + ExtParameterInfo() = default; + + /// Return the ABI treatment of this parameter. + ParameterABI getABI() const { return ParameterABI(Data & ABIMask); } + ExtParameterInfo withABI(ParameterABI kind) const { + ExtParameterInfo copy = *this; + copy.Data = (copy.Data & ~ABIMask) | unsigned(kind); + return copy; + } + + /// Is this parameter considered "consumed" by Objective-C ARC? + /// Consumed parameters must have retainable object type. + bool isConsumed() const { return (Data & IsConsumed); } + ExtParameterInfo withIsConsumed(bool consumed) const { + ExtParameterInfo copy = *this; + if (consumed) + copy.Data |= IsConsumed; + else + copy.Data &= ~IsConsumed; + return copy; + } + + bool hasPassObjectSize() const { return Data & HasPassObjSize; } + ExtParameterInfo withHasPassObjectSize() const { + ExtParameterInfo Copy = *this; + Copy.Data |= HasPassObjSize; + return Copy; + } + + bool isNoEscape() const { return Data & IsNoEscape; } + ExtParameterInfo withIsNoEscape(bool NoEscape) const { + ExtParameterInfo Copy = *this; + if (NoEscape) + Copy.Data |= IsNoEscape; + else + Copy.Data &= ~IsNoEscape; + return Copy; + } + + unsigned char getOpaqueValue() const { return Data; } + static ExtParameterInfo getFromOpaqueValue(unsigned char data) { + ExtParameterInfo result; + result.Data = data; + return result; + } + + friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) { + return lhs.Data == rhs.Data; + } + + friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) { + return lhs.Data != rhs.Data; + } + }; + /// A class which abstracts out some details necessary for /// making a call. /// @@ -3347,6 +3577,22 @@ public: } }; + /// A simple holder for a QualType representing a type in an + /// exception specification. Unfortunately needed by FunctionProtoType + /// because TrailingObjects cannot handle repeated types. + struct ExceptionType { QualType Type; }; + + /// A simple holder for various uncommon bits which do not fit in + /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the + /// alignment of subsequent objects in TrailingObjects. You must update + /// hasExtraBitfields in FunctionProtoType after adding extra data here. + struct alignas(void *) FunctionTypeExtraBitfields { + /// The number of types in the exception specification. + /// A whole unsigned is not needed here and according to + /// [implimits] 8 bits would be enough here. + unsigned NumExceptionType; + }; + protected: FunctionType(TypeClass tc, QualType res, QualType Canonical, bool Dependent, @@ -3359,7 +3605,9 @@ protected: FunctionTypeBits.ExtInfo = Info.Bits; } - unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; } + Qualifiers getFastTypeQuals() const { + return Qualifiers::fromFastMask(FunctionTypeBits.FastTypeQuals); + } public: QualType getReturnType() const { return ResultType; } @@ -3374,9 +3622,14 @@ public: CallingConv getCallConv() const { return getExtInfo().getCC(); } ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } - bool isConst() const { return getTypeQuals() & Qualifiers::Const; } - bool isVolatile() const { return getTypeQuals() & Qualifiers::Volatile; } - bool isRestrict() const { return getTypeQuals() & Qualifiers::Restrict; } + + static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0, + "Const, volatile and restrict are assumed to be a subset of " + "the fast qualifiers."); + + bool isConst() const { return getFastTypeQuals().hasConst(); } + bool isVolatile() const { return getFastTypeQuals().hasVolatile(); } + bool isRestrict() const { return getFastTypeQuals().hasRestrict(); } /// Determine the type of an expression that calls a function of /// this type. @@ -3426,104 +3679,65 @@ public: /// Represents a prototype with parameter type info, e.g. /// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no -/// parameters, not as having a single void parameter. Such a type can have an -/// exception specification, but this specification is not part of the canonical -/// type. -class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { -public: - /// Interesting information about a specific parameter that can't simply - /// be reflected in parameter's type. - /// - /// It makes sense to model language features this way when there's some - /// sort of parameter-specific override (such as an attribute) that - /// affects how the function is called. For example, the ARC ns_consumed - /// attribute changes whether a parameter is passed at +0 (the default) - /// or +1 (ns_consumed). This must be reflected in the function type, - /// but isn't really a change to the parameter type. - /// - /// One serious disadvantage of modelling language features this way is - /// that they generally do not work with language features that attempt - /// to destructure types. For example, template argument deduction will - /// not be able to match a parameter declared as - /// T (*)(U) - /// against an argument of type - /// void (*)(__attribute__((ns_consumed)) id) - /// because the substitution of T=void, U=id into the former will - /// not produce the latter. - class ExtParameterInfo { - enum { - ABIMask = 0x0F, - IsConsumed = 0x10, - HasPassObjSize = 0x20, - IsNoEscape = 0x40, - }; - unsigned char Data = 0; - - public: - ExtParameterInfo() = default; - - /// Return the ABI treatment of this parameter. - ParameterABI getABI() const { - return ParameterABI(Data & ABIMask); - } - ExtParameterInfo withABI(ParameterABI kind) const { - ExtParameterInfo copy = *this; - copy.Data = (copy.Data & ~ABIMask) | unsigned(kind); - return copy; - } - - /// Is this parameter considered "consumed" by Objective-C ARC? - /// Consumed parameters must have retainable object type. - bool isConsumed() const { - return (Data & IsConsumed); - } - ExtParameterInfo withIsConsumed(bool consumed) const { - ExtParameterInfo copy = *this; - if (consumed) { - copy.Data |= IsConsumed; - } else { - copy.Data &= ~IsConsumed; - } - return copy; - } - - bool hasPassObjectSize() const { - return Data & HasPassObjSize; - } - ExtParameterInfo withHasPassObjectSize() const { - ExtParameterInfo Copy = *this; - Copy.Data |= HasPassObjSize; - return Copy; - } - - bool isNoEscape() const { - return Data & IsNoEscape; - } - - ExtParameterInfo withIsNoEscape(bool NoEscape) const { - ExtParameterInfo Copy = *this; - if (NoEscape) - Copy.Data |= IsNoEscape; - else - Copy.Data &= ~IsNoEscape; - return Copy; - } - - unsigned char getOpaqueValue() const { return Data; } - static ExtParameterInfo getFromOpaqueValue(unsigned char data) { - ExtParameterInfo result; - result.Data = data; - return result; - } +/// parameters, not as having a single void parameter. Such a type can have +/// an exception specification, but this specification is not part of the +/// canonical type. FunctionProtoType has several trailing objects, some of +/// which optional. For more information about the trailing objects see +/// the first comment inside FunctionProtoType. +class FunctionProtoType final + : public FunctionType, + public llvm::FoldingSetNode, + private llvm::TrailingObjects< + FunctionProtoType, QualType, FunctionType::FunctionTypeExtraBitfields, + FunctionType::ExceptionType, Expr *, FunctionDecl *, + FunctionType::ExtParameterInfo, Qualifiers> { + friend class ASTContext; // ASTContext creates these. + friend TrailingObjects; - friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) { - return lhs.Data == rhs.Data; - } - friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) { - return lhs.Data != rhs.Data; - } - }; + // FunctionProtoType is followed by several trailing objects, some of + // which optional. They are in order: + // + // * An array of getNumParams() QualType holding the parameter types. + // Always present. Note that for the vast majority of FunctionProtoType, + // these will be the only trailing objects. + // + // * Optionally if some extra data is stored in FunctionTypeExtraBitfields + // (see FunctionTypeExtraBitfields and FunctionTypeBitfields): + // a single FunctionTypeExtraBitfields. Present if and only if + // hasExtraBitfields() is true. + // + // * Optionally exactly one of: + // * an array of getNumExceptions() ExceptionType, + // * a single Expr *, + // * a pair of FunctionDecl *, + // * a single FunctionDecl * + // used to store information about the various types of exception + // specification. See getExceptionSpecSize for the details. + // + // * Optionally an array of getNumParams() ExtParameterInfo holding + // an ExtParameterInfo for each of the parameters. Present if and + // only if hasExtParameterInfos() is true. + // + // * Optionally a Qualifiers object to represent extra qualifiers that can't + // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and only + // if hasExtQualifiers() is true. + // + // The optional FunctionTypeExtraBitfields has to be before the data + // related to the exception specification since it contains the number + // of exception types. + // + // We put the ExtParameterInfos last. If all were equal, it would make + // more sense to put these before the exception specification, because + // it's much easier to skip past them compared to the elaborate switch + // required to skip the exception specification. However, all is not + // equal; ExtParameterInfos are used to model very uncommon features, + // and it's better not to burden the more common paths. +public: + /// Holds information about the various types of exception specification. + /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is + /// used to group together the various bits of information about the + /// exception specification. struct ExceptionSpecInfo { /// The kind of exception specification this is. ExceptionSpecificationType Type = EST_None; @@ -3547,31 +3761,54 @@ public: ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {} }; - /// Extra information about a function prototype. + /// Extra information about a function prototype. ExtProtoInfo is not + /// stored as such in FunctionProtoType but is used to group together + /// the various bits of extra information about a function prototype. struct ExtProtoInfo { FunctionType::ExtInfo ExtInfo; bool Variadic : 1; bool HasTrailingReturn : 1; - unsigned char TypeQuals = 0; + Qualifiers TypeQuals; RefQualifierKind RefQualifier = RQ_None; ExceptionSpecInfo ExceptionSpec; const ExtParameterInfo *ExtParameterInfos = nullptr; - ExtProtoInfo() - : Variadic(false), HasTrailingReturn(false) {} + ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo(CallingConv CC) : ExtInfo(CC), Variadic(false), HasTrailingReturn(false) {} - ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &O) { + ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) { ExtProtoInfo Result(*this); - Result.ExceptionSpec = O; + Result.ExceptionSpec = ESI; return Result; } }; private: - friend class ASTContext; // ASTContext creates these. + unsigned numTrailingObjects(OverloadToken<QualType>) const { + return getNumParams(); + } + + unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const { + return hasExtraBitfields(); + } + + unsigned numTrailingObjects(OverloadToken<ExceptionType>) const { + return getExceptionSpecSize().NumExceptionType; + } + + unsigned numTrailingObjects(OverloadToken<Expr *>) const { + return getExceptionSpecSize().NumExprPtr; + } + + unsigned numTrailingObjects(OverloadToken<FunctionDecl *>) const { + return getExceptionSpecSize().NumFunctionDeclPtr; + } + + unsigned numTrailingObjects(OverloadToken<ExtParameterInfo>) const { + return hasExtParameterInfos() ? getNumParams() : 0; + } /// Determine whether there are any argument types that /// contain an unexpanded parameter pack. @@ -3587,88 +3824,71 @@ private: FunctionProtoType(QualType result, ArrayRef<QualType> params, QualType canonical, const ExtProtoInfo &epi); - /// The number of parameters this function has, not counting '...'. - unsigned NumParams : 15; - - /// The number of types in the exception spec, if any. - unsigned NumExceptions : 9; - - /// The type of exception specification this function has. - unsigned ExceptionSpecType : 4; - - /// Whether this function has extended parameter information. - unsigned HasExtParameterInfos : 1; - - /// Whether the function is variadic. - unsigned Variadic : 1; - - /// Whether this function has a trailing return type. - unsigned HasTrailingReturn : 1; - - // ParamInfo - There is an variable size array after the class in memory that - // holds the parameter types. - - // Exceptions - There is another variable size array after ArgInfo that - // holds the exception types. - - // NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing - // to the expression in the noexcept() specifier. - - // ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may - // be a pair of FunctionDecl* pointing to the function which should be used to - // instantiate this function type's exception specification, and the function - // from which it should be instantiated. - - // ExtParameterInfos - A variable size array, following the exception - // specification and of length NumParams, holding an ExtParameterInfo - // for each of the parameters. This only appears if HasExtParameterInfos - // is true. - - const ExtParameterInfo *getExtParameterInfosBuffer() const { - assert(hasExtParameterInfos()); - - // Find the end of the exception specification. - const auto *ptr = reinterpret_cast<const char *>(exception_begin()); - ptr += getExceptionSpecSize(); - - return reinterpret_cast<const ExtParameterInfo *>(ptr); - } + /// This struct is returned by getExceptionSpecSize and is used to + /// translate an ExceptionSpecificationType to the number and kind + /// of trailing objects related to the exception specification. + struct ExceptionSpecSizeHolder { + unsigned NumExceptionType; + unsigned NumExprPtr; + unsigned NumFunctionDeclPtr; + }; - static size_t getExceptionSpecSize(ExceptionSpecificationType EST, - unsigned NumExceptions) { + /// Return the number and kind of trailing objects + /// related to the exception specification. + static ExceptionSpecSizeHolder + getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) { switch (EST) { case EST_None: case EST_DynamicNone: case EST_MSAny: case EST_BasicNoexcept: case EST_Unparsed: - return 0; + return {0, 0, 0}; case EST_Dynamic: - return NumExceptions * sizeof(QualType); + return {NumExceptions, 0, 0}; case EST_DependentNoexcept: case EST_NoexceptFalse: case EST_NoexceptTrue: - return sizeof(Expr *); + return {0, 1, 0}; case EST_Uninstantiated: - return 2 * sizeof(FunctionDecl *); + return {0, 0, 2}; case EST_Unevaluated: - return sizeof(FunctionDecl *); + return {0, 0, 1}; } llvm_unreachable("bad exception specification kind"); } - size_t getExceptionSpecSize() const { + + /// Return the number and kind of trailing objects + /// related to the exception specification. + ExceptionSpecSizeHolder getExceptionSpecSize() const { return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions()); } + /// Whether the trailing FunctionTypeExtraBitfields is present. + static bool hasExtraBitfields(ExceptionSpecificationType EST) { + // If the exception spec type is EST_Dynamic then we have > 0 exception + // types and the exact number is stored in FunctionTypeExtraBitfields. + return EST == EST_Dynamic; + } + + /// Whether the trailing FunctionTypeExtraBitfields is present. + bool hasExtraBitfields() const { + return hasExtraBitfields(getExceptionSpecType()); + } + + bool hasExtQualifiers() const { + return FunctionTypeBits.HasExtQuals; + } + public: - unsigned getNumParams() const { return NumParams; } + unsigned getNumParams() const { return FunctionTypeBits.NumParams; } QualType getParamType(unsigned i) const { - assert(i < NumParams && "invalid parameter index"); + assert(i < getNumParams() && "invalid parameter index"); return param_type_begin()[i]; } @@ -3682,7 +3902,7 @@ public: EPI.Variadic = isVariadic(); EPI.HasTrailingReturn = hasTrailingReturn(); EPI.ExceptionSpec.Type = getExceptionSpecType(); - EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals()); + EPI.TypeQuals = getTypeQuals(); EPI.RefQualifier = getRefQualifier(); if (EPI.ExceptionSpec.Type == EST_Dynamic) { EPI.ExceptionSpec.Exceptions = exceptions(); @@ -3694,20 +3914,18 @@ public: } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); } - if (hasExtParameterInfos()) - EPI.ExtParameterInfos = getExtParameterInfosBuffer(); + EPI.ExtParameterInfos = getExtParameterInfosOrNull(); return EPI; } /// Get the kind of exception specification on this function. ExceptionSpecificationType getExceptionSpecType() const { - return static_cast<ExceptionSpecificationType>(ExceptionSpecType); + return static_cast<ExceptionSpecificationType>( + FunctionTypeBits.ExceptionSpecType); } /// Return whether this function has any kind of exception spec. - bool hasExceptionSpec() const { - return getExceptionSpecType() != EST_None; - } + bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; } /// Return whether this function has a dynamic (throw) exception spec. bool hasDynamicExceptionSpec() const { @@ -3726,16 +3944,26 @@ public: /// spec. bool hasInstantiationDependentExceptionSpec() const; - unsigned getNumExceptions() const { return NumExceptions; } + /// Return the number of types in the exception specification. + unsigned getNumExceptions() const { + return getExceptionSpecType() == EST_Dynamic + ? getTrailingObjects<FunctionTypeExtraBitfields>() + ->NumExceptionType + : 0; + } + + /// Return the ith exception type, where 0 <= i < getNumExceptions(). QualType getExceptionType(unsigned i) const { - assert(i < NumExceptions && "Invalid exception number!"); + assert(i < getNumExceptions() && "Invalid exception number!"); return exception_begin()[i]; } + + /// Return the expression inside noexcept(expression), or a null pointer + /// if there is none (because the exception spec is not of this form). Expr *getNoexceptExpr() const { if (!isComputedNoexcept(getExceptionSpecType())) return nullptr; - // NoexceptExpr sits where the arguments end. - return *reinterpret_cast<Expr *const *>(param_type_end()); + return *getTrailingObjects<Expr *>(); } /// If this function type has an exception specification which hasn't @@ -3746,7 +3974,7 @@ public: if (getExceptionSpecType() != EST_Uninstantiated && getExceptionSpecType() != EST_Unevaluated) return nullptr; - return reinterpret_cast<FunctionDecl *const *>(param_type_end())[0]; + return getTrailingObjects<FunctionDecl *>()[0]; } /// If this function type has an uninstantiated exception @@ -3756,7 +3984,7 @@ public: FunctionDecl *getExceptionSpecTemplate() const { if (getExceptionSpecType() != EST_Uninstantiated) return nullptr; - return reinterpret_cast<FunctionDecl *const *>(param_type_end())[1]; + return getTrailingObjects<FunctionDecl *>()[1]; } /// Determine whether this function type has a non-throwing exception @@ -3767,11 +3995,11 @@ public: /// specification. If this depends on template arguments, returns /// \c ResultIfDependent. bool isNothrow(bool ResultIfDependent = false) const { - return ResultIfDependent ? canThrow() != CT_Can - : canThrow() == CT_Cannot; + return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot; } - bool isVariadic() const { return Variadic; } + /// Whether this function prototype is variadic. + bool isVariadic() const { return FunctionTypeBits.Variadic; } /// Determines whether this function prototype contains a /// parameter pack at the end. @@ -3781,9 +4009,15 @@ public: /// function. bool isTemplateVariadic() const; - bool hasTrailingReturn() const { return HasTrailingReturn; } + /// Whether this function prototype has a trailing return type. + bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; } - unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } + Qualifiers getTypeQuals() const { + if (hasExtQualifiers()) + return *getTrailingObjects<Qualifiers>(); + else + return getFastTypeQuals(); + } /// Retrieve the ref-qualifier associated with this function type. RefQualifierKind getRefQualifier() const { @@ -3798,11 +4032,11 @@ public: } param_type_iterator param_type_begin() const { - return reinterpret_cast<const QualType *>(this+1); + return getTrailingObjects<QualType>(); } param_type_iterator param_type_end() const { - return param_type_begin() + NumParams; + return param_type_begin() + getNumParams(); } using exception_iterator = const QualType *; @@ -3812,22 +4046,23 @@ public: } exception_iterator exception_begin() const { - // exceptions begin where arguments end - return param_type_end(); + return reinterpret_cast<exception_iterator>( + getTrailingObjects<ExceptionType>()); } exception_iterator exception_end() const { - if (getExceptionSpecType() != EST_Dynamic) - return exception_begin(); - return exception_begin() + NumExceptions; + return exception_begin() + getNumExceptions(); } /// Is there any interesting extra information for any of the parameters /// of this function type? - bool hasExtParameterInfos() const { return HasExtParameterInfos; } + bool hasExtParameterInfos() const { + return FunctionTypeBits.HasExtParameterInfos; + } + ArrayRef<ExtParameterInfo> getExtParameterInfos() const { assert(hasExtParameterInfos()); - return ArrayRef<ExtParameterInfo>(getExtParameterInfosBuffer(), + return ArrayRef<ExtParameterInfo>(getTrailingObjects<ExtParameterInfo>(), getNumParams()); } @@ -3837,27 +4072,27 @@ public: const ExtParameterInfo *getExtParameterInfosOrNull() const { if (!hasExtParameterInfos()) return nullptr; - return getExtParameterInfosBuffer(); + return getTrailingObjects<ExtParameterInfo>(); } ExtParameterInfo getExtParameterInfo(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) - return getExtParameterInfosBuffer()[I]; + return getTrailingObjects<ExtParameterInfo>()[I]; return ExtParameterInfo(); } ParameterABI getParameterABI(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) - return getExtParameterInfosBuffer()[I].getABI(); + return getTrailingObjects<ExtParameterInfo>()[I].getABI(); return ParameterABI::Ordinary; } bool isParamConsumed(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) - return getExtParameterInfosBuffer()[I].isConsumed(); + return getTrailingObjects<ExtParameterInfo>()[I].isConsumed(); return false; } @@ -4189,56 +4424,7 @@ public: /// - the canonical type is VectorType(16, int) class AttributedType : public Type, public llvm::FoldingSetNode { public: - // It is really silly to have yet another attribute-kind enum, but - // clang::attr::Kind doesn't currently cover the pure type attrs. - enum Kind { - // Expression operand. - attr_address_space, - attr_regparm, - attr_vector_size, - attr_neon_vector_type, - attr_neon_polyvector_type, - - FirstExprOperandKind = attr_address_space, - LastExprOperandKind = attr_neon_polyvector_type, - - // Enumerated operand (string or keyword). - attr_objc_gc, - attr_objc_ownership, - attr_pcs, - attr_pcs_vfp, - - FirstEnumOperandKind = attr_objc_gc, - LastEnumOperandKind = attr_pcs_vfp, - - // No operand. - attr_noreturn, - attr_nocf_check, - attr_cdecl, - attr_fastcall, - attr_stdcall, - attr_thiscall, - attr_regcall, - attr_pascal, - attr_swiftcall, - attr_vectorcall, - attr_inteloclbicc, - attr_ms_abi, - attr_sysv_abi, - attr_preserve_most, - attr_preserve_all, - attr_ptr32, - attr_ptr64, - attr_sptr, - attr_uptr, - attr_nonnull, - attr_ns_returns_retained, - attr_nullable, - attr_null_unspecified, - attr_objc_kindof, - attr_objc_inert_unsafe_unretained, - attr_lifetimebound, - }; + using Kind = attr::Kind; private: friend class ASTContext; // ASTContext creates these @@ -4246,7 +4432,7 @@ private: QualType ModifiedType; QualType EquivalentType; - AttributedType(QualType canon, Kind attrKind, QualType modified, + AttributedType(QualType canon, attr::Kind attrKind, QualType modified, QualType equivalent) : Type(Attributed, canon, equivalent->isDependentType(), equivalent->isInstantiationDependentType(), @@ -4295,13 +4481,13 @@ public: static Kind getNullabilityAttrKind(NullabilityKind kind) { switch (kind) { case NullabilityKind::NonNull: - return attr_nonnull; + return attr::TypeNonNull; case NullabilityKind::Nullable: - return attr_nullable; + return attr::TypeNullable; case NullabilityKind::Unspecified: - return attr_null_unspecified; + return attr::TypeNullUnspecified; } llvm_unreachable("Unknown nullability kind."); } @@ -4480,9 +4666,6 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { /// parameter pack is instantiated with. const TemplateArgument *Arguments; - /// The number of template arguments in \c Arguments. - unsigned NumArguments; - SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, QualType Canon, const TemplateArgument &ArgPack); @@ -4495,6 +4678,10 @@ public: return Replaced; } + unsigned getNumArgs() const { + return SubstTemplateTypeParmPackTypeBits.NumArgs; + } + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -4665,13 +4852,6 @@ class alignas(8) TemplateSpecializationType /// replacement must, recursively, be one of these). TemplateName Template; - /// The number of template arguments named in this class template - /// specialization. - unsigned NumArgs : 31; - - /// Whether this template specialization type is a substituted type alias. - unsigned TypeAlias : 1; - TemplateSpecializationType(TemplateName T, ArrayRef<TemplateArgument> Args, QualType Canon, @@ -4706,7 +4886,7 @@ public: /// typedef A<Ts...> type; // not a type alias /// }; /// \endcode - bool isTypeAlias() const { return TypeAlias; } + bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; } /// Get the aliased type, if this is a specialization of a type alias /// template. @@ -4729,21 +4909,25 @@ public: } /// Retrieve the number of template arguments. - unsigned getNumArgs() const { return NumArgs; } + unsigned getNumArgs() const { + return TemplateSpecializationTypeBits.NumArgs; + } /// Retrieve a specific template argument as a type. /// \pre \c isArgType(Arg) const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h ArrayRef<TemplateArgument> template_arguments() const { - return {getArgs(), NumArgs}; + return {getArgs(), getNumArgs()}; } bool isSugared() const { return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); } - QualType desugar() const { return getCanonicalTypeInternal(); } + QualType desugar() const { + return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal(); + } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, Template, template_arguments(), Ctx); @@ -4942,8 +5126,12 @@ public: /// source code, including tag keywords and any nested-name-specifiers. /// The type itself is always "sugar", used to express what was written /// in the source code but containing no additional semantic information. -class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode { +class ElaboratedType final + : public TypeWithKeyword, + public llvm::FoldingSetNode, + private llvm::TrailingObjects<ElaboratedType, TagDecl *> { friend class ASTContext; // ASTContext creates these + friend TrailingObjects; /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; @@ -4951,26 +5139,29 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode { /// The type that this qualified name refers to. QualType NamedType; - /// The (re)declaration of this tag type owned by this occurrence, or nullptr - /// if none. - TagDecl *OwnedTagDecl; + /// The (re)declaration of this tag type owned by this occurrence is stored + /// as a trailing object if there is one. Use getOwnedTagDecl to obtain + /// it, or obtain a null pointer if there is none. ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl) - : TypeWithKeyword(Keyword, Elaborated, CanonType, - NamedType->isDependentType(), - NamedType->isInstantiationDependentType(), - NamedType->isVariablyModifiedType(), - NamedType->containsUnexpandedParameterPack()), - NNS(NNS), NamedType(NamedType), OwnedTagDecl(OwnedTagDecl) { + : TypeWithKeyword(Keyword, Elaborated, CanonType, + NamedType->isDependentType(), + NamedType->isInstantiationDependentType(), + NamedType->isVariablyModifiedType(), + NamedType->containsUnexpandedParameterPack()), + NNS(NNS), NamedType(NamedType) { + ElaboratedTypeBits.HasOwnedTagDecl = false; + if (OwnedTagDecl) { + ElaboratedTypeBits.HasOwnedTagDecl = true; + *getTrailingObjects<TagDecl *>() = OwnedTagDecl; + } assert(!(Keyword == ETK_None && NNS == nullptr) && "ElaboratedType cannot have elaborated type keyword " "and name qualifier both null."); } public: - ~ElaboratedType(); - /// Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } @@ -4984,11 +5175,14 @@ public: bool isSugared() const { return true; } /// Return the (re)declaration of this type owned by this occurrence of this - /// type, or nullptr if none. - TagDecl *getOwnedTagDecl() const { return OwnedTagDecl; } + /// type, or nullptr if there is none. + TagDecl *getOwnedTagDecl() const { + return ElaboratedTypeBits.HasOwnedTagDecl ? *getTrailingObjects<TagDecl *>() + : nullptr; + } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getKeyword(), NNS, NamedType, OwnedTagDecl); + Profile(ID, getKeyword(), NNS, NamedType, getOwnedTagDecl()); } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, @@ -5000,9 +5194,7 @@ public: ID.AddPointer(OwnedTagDecl); } - static bool classof(const Type *T) { - return T->getTypeClass() == Elaborated; - } + static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; } }; /// Represents a qualified type name for which the type name is @@ -5080,10 +5272,6 @@ class alignas(8) DependentTemplateSpecializationType /// The identifier of the template. const IdentifierInfo *Name; - /// The number of template arguments named in this class template - /// specialization. - unsigned NumArgs; - DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, @@ -5108,12 +5296,14 @@ public: } /// Retrieve the number of template arguments. - unsigned getNumArgs() const { return NumArgs; } + unsigned getNumArgs() const { + return DependentTemplateSpecializationTypeBits.NumArgs; + } const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h ArrayRef<TemplateArgument> template_arguments() const { - return {getArgs(), NumArgs}; + return {getArgs(), getNumArgs()}; } using iterator = const TemplateArgument *; @@ -5125,7 +5315,7 @@ public: QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getKeyword(), NNS, Name, {getArgs(), NumArgs}); + Profile(ID, Context, getKeyword(), NNS, Name, {getArgs(), getNumArgs()}); } static void Profile(llvm::FoldingSetNodeID &ID, @@ -5168,22 +5358,16 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode { /// The pattern of the pack expansion. QualType Pattern; - /// The number of expansions that this pack expansion will - /// generate when substituted (+1), or indicates that - /// - /// This field will only have a non-zero value when some of the parameter - /// packs that occur within the pattern have been substituted but others have - /// not. - unsigned NumExpansions; - PackExpansionType(QualType Pattern, QualType Canon, Optional<unsigned> NumExpansions) : Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(), /*InstantiationDependent=*/true, /*VariablyModified=*/Pattern->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false), - Pattern(Pattern), - NumExpansions(NumExpansions ? *NumExpansions + 1 : 0) {} + Pattern(Pattern) { + PackExpansionTypeBits.NumExpansions = + NumExpansions ? *NumExpansions + 1 : 0; + } public: /// Retrieve the pattern of this pack expansion, which is the @@ -5194,9 +5378,8 @@ public: /// Retrieve the number of expansions that this pack expansion will /// generate, if known. Optional<unsigned> getNumExpansions() const { - if (NumExpansions) - return NumExpansions - 1; - + if (PackExpansionTypeBits.NumExpansions) + return PackExpansionTypeBits.NumExpansions - 1; return None; } @@ -6295,9 +6478,30 @@ inline bool Type::isPipeType() const { return isa<PipeType>(CanonicalType); } +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ + inline bool Type::is##Id##Type() const { \ + return isSpecificBuiltinType(BuiltinType::Id); \ + } +#include "clang/Basic/OpenCLExtensionTypes.def" + +inline bool Type::isOCLIntelSubgroupAVCType() const { +#define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \ + isOCLIntelSubgroupAVC##Id##Type() || + return +#include "clang/Basic/OpenCLExtensionTypes.def" + false; // end of boolean or operation +} + +inline bool Type::isOCLExtOpaqueType() const { +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() || + return +#include "clang/Basic/OpenCLExtensionTypes.def" + false; // end of boolean or operation +} + inline bool Type::isOpenCLSpecificType() const { return isSamplerT() || isEventT() || isImageType() || isClkEventT() || - isQueueT() || isReserveIDT() || isPipeType(); + isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType(); } inline bool Type::isTemplateTypeParmType() const { @@ -6497,6 +6701,24 @@ inline const Type *Type::getPointeeOrArrayElementType() const { return type; } +/// Insertion operator for diagnostics. This allows sending Qualifiers into a +/// diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + Qualifiers Q) { + DB.AddTaggedVal(Q.getAsOpaqueValue(), + DiagnosticsEngine::ArgumentKind::ak_qual); + return DB; +} + +/// Insertion operator for partial diagnostics. This allows sending Qualifiers +/// into a diagnostic with <<. +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + Qualifiers Q) { + PD.AddTaggedVal(Q.getAsOpaqueValue(), + DiagnosticsEngine::ArgumentKind::ak_qual); + return PD; +} + /// Insertion operator for diagnostics. This allows sending QualType's into a /// diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, @@ -6619,9 +6841,8 @@ QualType DecayedType::getPointeeType() const { // Get the decimal string representation of a fixed point type, represented // as a scaled integer. -void FixedPointValueToString(SmallVectorImpl<char> &Str, - const llvm::APSInt &Val, - unsigned Scale, unsigned Radix); +void FixedPointValueToString(SmallVectorImpl<char> &Str, llvm::APSInt Val, + unsigned Scale); } // namespace clang diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index c69f4aa4abcf..1e89e9386719 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_AST_TYPELOC_H #define LLVM_CLANG_AST_TYPELOC_H +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" @@ -151,8 +152,6 @@ public: return SourceRange(getBeginLoc(), getEndLoc()); } - SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); } - SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } /// Get the local source range. SourceRange getLocalSourceRange() const { @@ -843,16 +842,7 @@ class SubstTemplateTypeParmPackTypeLoc : }; struct AttributedLocInfo { - union { - Expr *ExprOperand; - - /// A raw SourceLocation. - unsigned EnumOperandLoc; - }; - - SourceRange OperandParens; - - SourceLocation AttrLoc; + const Attr *TypeAttr; }; /// Type source information for an attributed type. @@ -861,24 +851,10 @@ class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AttributedType, AttributedLocInfo> { public: - AttributedType::Kind getAttrKind() const { + attr::Kind getAttrKind() const { return getTypePtr()->getAttrKind(); } - bool hasAttrExprOperand() const { - return (getAttrKind() >= AttributedType::FirstExprOperandKind && - getAttrKind() <= AttributedType::LastExprOperandKind); - } - - bool hasAttrEnumOperand() const { - return (getAttrKind() >= AttributedType::FirstEnumOperandKind && - getAttrKind() <= AttributedType::LastEnumOperandKind); - } - - bool hasAttrOperand() const { - return hasAttrExprOperand() || hasAttrEnumOperand(); - } - bool isQualifier() const { return getTypePtr()->isQualifier(); } @@ -891,51 +867,16 @@ public: return getInnerTypeLoc(); } - /// The location of the attribute name, i.e. - /// __attribute__((regparm(1000))) - /// ^~~~~~~ - SourceLocation getAttrNameLoc() const { - return getLocalData()->AttrLoc; + /// The type attribute. + const Attr *getAttr() const { + return getLocalData()->TypeAttr; } - void setAttrNameLoc(SourceLocation loc) { - getLocalData()->AttrLoc = loc; + void setAttr(const Attr *A) { + getLocalData()->TypeAttr = A; } - /// The attribute's expression operand, if it has one. - /// void *cur_thread __attribute__((address_space(21))) - /// ^~ - Expr *getAttrExprOperand() const { - assert(hasAttrExprOperand()); - return getLocalData()->ExprOperand; - } - void setAttrExprOperand(Expr *e) { - assert(hasAttrExprOperand()); - getLocalData()->ExprOperand = e; - } - - /// The location of the attribute's enumerated operand, if it has one. - /// void * __attribute__((objc_gc(weak))) - /// ^~~~ - SourceLocation getAttrEnumOperandLoc() const { - assert(hasAttrEnumOperand()); - return SourceLocation::getFromRawEncoding(getLocalData()->EnumOperandLoc); - } - void setAttrEnumOperandLoc(SourceLocation loc) { - assert(hasAttrEnumOperand()); - getLocalData()->EnumOperandLoc = loc.getRawEncoding(); - } - - /// The location of the parentheses around the operand, if there is - /// an operand. - /// void * __attribute__((objc_gc(weak))) - /// ^ ^ - SourceRange getAttrOperandParensRange() const { - assert(hasAttrOperand()); - return getLocalData()->OperandParens; - } - void setAttrOperandParensRange(SourceRange range) { - assert(hasAttrOperand()); - getLocalData()->OperandParens = range; + template<typename T> const T *getAttrAs() { + return dyn_cast_or_null<T>(getAttr()); } SourceRange getLocalSourceRange() const { @@ -948,21 +889,11 @@ public: // ^~ ~~ // That enclosure doesn't necessarily belong to a single attribute // anyway. - SourceRange range(getAttrNameLoc()); - if (hasAttrOperand()) - range.setEnd(getAttrOperandParensRange().getEnd()); - return range; + return getAttr() ? getAttr()->getRange() : SourceRange(); } void initializeLocal(ASTContext &Context, SourceLocation loc) { - setAttrNameLoc(loc); - if (hasAttrExprOperand()) { - setAttrOperandParensRange(SourceRange(loc)); - setAttrExprOperand(nullptr); - } else if (hasAttrEnumOperand()) { - setAttrOperandParensRange(SourceRange(loc)); - setAttrEnumOperandLoc(loc); - } + setAttr(nullptr); } QualType getInnerType() const { |
