diff options
Diffstat (limited to 'include/clang/AST')
29 files changed, 3889 insertions, 1215 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 5b693eb97f..7edf3b3fed 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -569,26 +569,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 { @@ -630,7 +610,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) @@ -1062,6 +1052,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'. @@ -2921,13 +2914,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 { diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h index 2534272da3..fe92604587 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 0000000000..129c40ce3e --- /dev/null +++ b/include/clang/AST/ASTDumperUtils.h @@ -0,0 +1,181 @@ +//===--- 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 "clang/AST/ASTContext.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 { + raw_ostream::Colors Color; + bool Bold; +}; + +// Red - CastColor +// Green - TypeColor +// Bold Green - DeclKindNameColor, UndeserializedColor +// Yellow - AddressColor, LocationColor +// Blue - CommentColor, NullColor, IndentColor +// Bold Blue - AttrColor +// Bold Magenta - StmtColor +// Cyan - ValueKindColor, ObjectKindColor +// Bold Cyan - ValueColor, DeclNameColor + +// Decl kind names (VarDecl, FunctionDecl, etc) +static const TerminalColor DeclKindNameColor = {raw_ostream::GREEN, true}; +// Attr names (CleanupAttr, GuardedByAttr, etc) +static const TerminalColor AttrColor = {raw_ostream::BLUE, true}; +// Statement names (DeclStmt, ImplicitCastExpr, etc) +static const TerminalColor StmtColor = {raw_ostream::MAGENTA, true}; +// Comment names (FullComment, ParagraphComment, TextComment, etc) +static const TerminalColor CommentColor = {raw_ostream::BLUE, false}; + +// Type names (int, float, etc, plus user defined types) +static const TerminalColor TypeColor = {raw_ostream::GREEN, false}; + +// Pointer address +static const TerminalColor AddressColor = {raw_ostream::YELLOW, false}; +// Source locations +static const TerminalColor LocationColor = {raw_ostream::YELLOW, false}; + +// lvalue/xvalue +static const TerminalColor ValueKindColor = {raw_ostream::CYAN, false}; +// bitfield/objcproperty/objcsubscript/vectorcomponent +static const TerminalColor ObjectKindColor = {raw_ostream::CYAN, false}; + +// Null statements +static const TerminalColor NullColor = {raw_ostream::BLUE, false}; + +// Undeserialized entities +static const TerminalColor UndeserializedColor = {raw_ostream::GREEN, true}; + +// CastKind from CastExpr's +static const TerminalColor CastColor = {raw_ostream::RED, false}; + +// Value of the statement +static const TerminalColor ValueColor = {raw_ostream::CYAN, true}; +// Decl names +static const TerminalColor DeclNameColor = {raw_ostream::CYAN, true}; + +// Indents ( `, -. | ) +static const TerminalColor IndentColor = {raw_ostream::BLUE, false}; + +class ColorScope { + raw_ostream &OS; + const bool ShowColors; + +public: + ColorScope(raw_ostream &OS, bool ShowColors, TerminalColor Color) + : OS(OS), ShowColors(ShowColors) { + if (ShowColors) + OS.changeColor(Color.Color, Color.Bold); + } + ~ColorScope() { + if (ShowColors) + OS.resetColor(); + } +}; + +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) { + // 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; + } + + auto dumpWithIndent = [this, doAddChild](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 ? '`' : '|') << '-'; + 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) {} +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_ASTDUMPERUTILS_H diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h index 311d64e7cb..cbd5c3414b 100644 --- a/include/clang/AST/ASTImporter.h +++ b/include/clang/AST/ASTImporter.h @@ -25,7 +25,9 @@ #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 { @@ -43,6 +45,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. @@ -122,31 +147,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 +209,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 @@ -336,9 +423,9 @@ class Attr; /// 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 1. - /// 0 is returned on error (parent context is non-record). - static unsigned getFieldIndex(Decl *F); + /// \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); }; diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 0e738da43a..c2f01e7d54 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/CommentDiagnostic.h b/include/clang/AST/CommentDiagnostic.h index f3a209bf6e..b9816f1a8e 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 d1cc2d0a4e..e37e9d6cd2 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 2b6e111106..3145f35ead 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -965,6 +965,8 @@ protected: /// Defines kind of the ImplicitParamDecl: 'this', 'self', 'vtt', '_cmd' or /// something else. unsigned ImplicitParamKind : 3; + + unsigned EscapingByref : 1; }; union { @@ -1407,6 +1409,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; @@ -1704,6 +1719,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, @@ -2211,6 +2233,12 @@ public: 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; @@ -2218,6 +2246,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; @@ -3865,6 +3897,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; } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 23870400a3..8405a43fa0 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -1065,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(); @@ -1082,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)) @@ -1212,7 +1213,6 @@ public: value_type SingleElement; public: - iterator() = default; explicit iterator(pointer Pos, value_type Single = nullptr) : IteratorBase(Pos), SingleElement(Single) {} diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index cb1de0bc57..58e01bf0f0 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1541,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(); } @@ -2182,7 +2182,10 @@ public: /// 'this' type. QualType getThisType(ASTContext &C) const; - unsigned getTypeQualifiers() const { + static QualType getThisType(const FunctionProtoType *FPT, + const CXXRecordDecl *Decl); + + Qualifiers getTypeQualifiers() const { return getType()->getAs<FunctionProtoType>()->getTypeQuals(); } @@ -2315,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; diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index e0ea7cb8b1..9e01c4950d 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -1093,6 +1093,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 520a4a10bf..c6cbc9ff7f 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/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h index 1aec5ae842..f356584144 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 8bc14e12df..d57c45eec0 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; @@ -582,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 @@ -599,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 @@ -631,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; @@ -863,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. //===----------------------------------------------------------------------===// @@ -973,61 +1044,60 @@ 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, 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; + : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), + D(D), DNLoc(LocInfo) { + DeclRefExprBits.HasQualifier = false; + DeclRefExprBits.HasTemplateKWAndArgsInfo = false; + DeclRefExprBits.HasFoundDecl = false; + DeclRefExprBits.HadMultipleCandidates = false; DeclRefExprBits.RefersToEnclosingVariableOrCapture = RefersToEnclosingVariableOrCapture; + DeclRefExprBits.Loc = L; computeDependence(D->getASTContext()); } @@ -1047,8 +1117,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); @@ -1058,11 +1127,11 @@ 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 getLocation() const { return DeclRefExprBits.Loc; } + void setLocation(SourceLocation L) { DeclRefExprBits.Loc = L; } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; @@ -1107,21 +1176,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; } @@ -1146,7 +1218,6 @@ public: const TemplateArgumentLoc *getTemplateArgs() const { if (!hasExplicitTemplateArgs()) return nullptr; - return getTrailingObjects<TemplateArgumentLoc>(); } @@ -1155,7 +1226,6 @@ public: unsigned getNumTemplateArgs() const { if (!hasExplicitTemplateArgs()) return 0; - return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->NumTemplateArgs; } @@ -1193,68 +1263,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 getBeginLoc() const LLVM_READONLY { return Loc; } - SourceLocation getEndLoc() 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 @@ -1550,14 +1558,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, @@ -1565,131 +1574,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]; - - StringLiteral(QualType Ty) : - Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false, - false) {} - - static int mapCharByteWidth(TargetInfo const &target,StringKind k); + unsigned numTrailingObjects(OverloadToken<char>) const { + return getByteLength(); + } + + char *getStrDataAsChar() { return getTrailingObjects<char>(); } + const char *getStrDataAsChar() const { return getTrailingObjects<char>(); } + + 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); + + /// 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 @@ -1706,14 +1740,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 getBeginLoc() const LLVM_READONLY { return TokLocs[0]; } - SourceLocation getEndLoc() 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; } @@ -1727,6 +1765,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 { @@ -1782,15 +1905,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, @@ -1799,21 +1918,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++; @@ -1821,8 +1947,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) { @@ -1874,12 +2000,12 @@ public: static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); SourceLocation getBeginLoc() const LLVM_READONLY { - return isPostfix() ? Val->getBeginLoc() : Loc; + return isPostfix() ? Val->getBeginLoc() : getOperatorLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { - return isPostfix() ? Loc : Val->getEndLoc(); + 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; @@ -2195,9 +2321,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, @@ -2208,10 +2336,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. @@ -2235,29 +2363,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(); - } - - const Expr *getBase() const { - return getRHS()->getType()->isIntegerType() ? getLHS() : getRHS(); - } - - Expr *getIdx() { - return getRHS()->getType()->isIntegerType() ? getRHS() : getLHS(); - } + Expr *getBase() { return lhsIsBase() ? getLHS() : getRHS(); } + const Expr *getBase() const { return lhsIsBase() ? getLHS() : getRHS(); } - const Expr *getIdx() const { - return getRHS()->getType()->isIntegerType() ? getRHS() : getLHS(); - } + Expr *getIdx() { return lhsIsBase() ? getRHS() : getLHS(); } + const Expr *getIdx() const { return lhsIsBase() ? getRHS() : getLHS(); } SourceLocation getBeginLoc() const LLVM_READONLY { return getLHS()->getBeginLoc(); } - SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; } + SourceLocation getEndLoc() const { return getRBracketLoc(); } - SourceLocation getRBracketLoc() const { return RBracketLoc; } - void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } + SourceLocation getRBracketLoc() const { + return ArraySubscriptExprBits.RBracketLoc; + } + void setRBracketLoc(SourceLocation L) { + ArraySubscriptExprBits.RBracketLoc = L; + } SourceLocation getExprLoc() const LLVM_READONLY { return getBase()->getExprLoc(); @@ -2290,15 +2412,22 @@ class CallExpr : public Expr { void updateDependenciesFromArg(Expr *Arg); +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); + ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0, + ADLCallKind UsesADL = NotADL); CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> args, - QualType t, ExprValueKind VK, SourceLocation rparenloc); + QualType t, ExprValueKind VK, SourceLocation rparenloc, + unsigned MinNumArgs = 0, ADLCallKind UsesADL = NotADL); CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs, - EmptyShell Empty); + unsigned NumArgs, EmptyShell Empty); Stmt *getPreArg(unsigned i) { assert(i < getNumPreArgs() && "Prearg access out of range!"); @@ -2316,16 +2445,28 @@ protected: unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; } public: - CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t, - ExprValueKind VK, SourceLocation rparenloc); + /// Build a call expression. MinNumArgs specifies the minimum number of + /// arguments. The actual number of arguments will be the greater of + /// args.size() and MinNumArgs. + CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t, + ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0, + ADLCallKind UsesADL = NotADL); /// Build an empty call expression. - CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty); + CallExpr(const ASTContext &C, unsigned NumArgs, EmptyShell Empty); const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); } Expr *getCallee() { return cast<Expr>(SubExprs[FN]); } void setCallee(Expr *F) { SubExprs[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(); const Decl *getCalleeDecl() const { return const_cast<CallExpr*>(this)->getCalleeDecl(); @@ -2366,10 +2507,18 @@ public: SubExprs[Arg+getNumPreArgs()+PREARGS_START] = 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 will + /// be stored in a trailing array in the future. + /// (TODO: update this comment when this is done). + void shrinkNumArgs(unsigned NewNumArgs) { + assert((NewNumArgs <= NumArgs) && + "shrinkNumArgs cannot increase the number of arguments!"); + NumArgs = NewNumArgs; + } typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; @@ -2469,6 +2618,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; @@ -2484,35 +2637,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: @@ -2523,10 +2661,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 @@ -2539,10 +2680,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, @@ -2565,7 +2709,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; @@ -2580,9 +2724,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; } @@ -2596,21 +2739,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; } @@ -2657,10 +2803,10 @@ 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'. @@ -2680,13 +2826,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. @@ -2706,10 +2852,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] @@ -2932,8 +3074,7 @@ class ImplicitCastExpr final 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) @@ -2976,8 +3117,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; } @@ -3100,20 +3246,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 : 3; - 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, @@ -3124,8 +3261,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() && @@ -3133,15 +3272,18 @@ 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; } @@ -3170,7 +3312,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; } @@ -3269,21 +3415,23 @@ 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 FPOptions(FPFeatures).allowFEnvAccess(); - } + bool isFEnvAccessOn() const { return getFPFeatures().allowFEnvAccess(); } protected: BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, @@ -3295,14 +3443,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 @@ -4726,31 +4877,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); + + /// Create an empty paren list. + static ParenListExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumExprs); - unsigned getNumExprs() const { return NumExprs; } + /// Return the number of expressions in this paren list. + unsigned getNumExprs() const { return ParenListExprBits.NumExprs; } - const Expr* getExpr(unsigned Init) const { + 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()); @@ -4758,9 +4924,8 @@ public: SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } - - SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; } - SourceLocation getEndLoc() 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; @@ -4768,14 +4933,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. diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 8fbd53798a..f39bddb040 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -90,16 +90,20 @@ public: friend class ASTStmtReader; friend class ASTStmtWriter; - 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), + CXXOperatorCallExpr(ASTContext &C, OverloadedOperatorKind Op, Expr *fn, + ArrayRef<Expr *> args, QualType t, ExprValueKind VK, + SourceLocation operatorloc, FPOptions FPFeatures, + ADLCallKind UsesADL = NotADL) + : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc, + /*MinNumArgs=*/0, UsesADL), Operator(Op), FPFeatures(FPFeatures) { Range = getSourceRangeImpl(); } - explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) - : CallExpr(C, CXXOperatorCallExprClass, Empty) {} + explicit CXXOperatorCallExpr(ASTContext &C, unsigned NumArgs, + EmptyShell Empty) + : CallExpr(C, CXXOperatorCallExprClass, /*NumPreArgs=*/0, NumArgs, + Empty) {} /// Returns the kind of overloaded operator that this /// expression refers to. @@ -163,12 +167,14 @@ public: /// the object argument). class CXXMemberCallExpr : public CallExpr { public: - CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> args, - QualType t, ExprValueKind VK, SourceLocation RP) - : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP) {} + CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t, + ExprValueKind VK, SourceLocation RP, + unsigned MinNumArgs = 0) + : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP, MinNumArgs, + NotADL) {} - CXXMemberCallExpr(ASTContext &C, EmptyShell Empty) - : CallExpr(C, CXXMemberCallExprClass, Empty) {} + CXXMemberCallExpr(ASTContext &C, unsigned NumArgs, EmptyShell Empty) + : CallExpr(C, CXXMemberCallExprClass, /*NumPreArgs=*/0, NumArgs, Empty) {} /// Retrieves the implicit object argument for the member call. /// @@ -206,12 +212,14 @@ private: 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) {} + ArrayRef<Expr *> args, QualType t, ExprValueKind VK, + SourceLocation RP, unsigned MinNumArgs = 0) + : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP, + MinNumArgs, NotADL) {} - CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty) - : CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) {} + CUDAKernelCallExpr(ASTContext &C, unsigned NumArgs, EmptyShell Empty) + : CallExpr(C, CUDAKernelCallExprClass, /*NumPreArgs=*/END_PREARG, NumArgs, + Empty) {} const CallExpr *getConfig() const { return cast_or_null<CallExpr>(getPreArg(CONFIG)); @@ -482,14 +490,17 @@ public: friend class ASTStmtReader; friend class ASTStmtWriter; - UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args, + 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), + : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc, + /*MinNumArgs=*/0, NotADL), UDSuffixLoc(SuffixLoc) {} - explicit UserDefinedLiteral(const ASTContext &C, EmptyShell Empty) - : CallExpr(C, UserDefinedLiteralClass, Empty) {} + explicit UserDefinedLiteral(const ASTContext &C, unsigned NumArgs, + EmptyShell Empty) + : CallExpr(C, UserDefinedLiteralClass, /*NumPreArgs=*/0, NumArgs, Empty) { + } /// The kind of literal operator which is invoked. enum LiteralOperatorKind { @@ -548,26 +559,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 getBeginLoc() const LLVM_READONLY { return Loc; } - SourceLocation getEndLoc() 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 +593,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 getBeginLoc() const LLVM_READONLY { return Loc; } - SourceLocation getEndLoc() 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; @@ -964,29 +973,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 getBeginLoc() const LLVM_READONLY { return Loc; } - SourceLocation getEndLoc() 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,42 +1014,43 @@ 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 getBeginLoc() const LLVM_READONLY { return ThrowLoc; } + bool isThrownVariableInScope() const { + return CXXThrowExprBits.IsThrownVariableInScope; + } + SourceLocation getBeginLoc() const { return getThrowLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { if (!getSubExpr()) - return ThrowLoc; + return getThrowLoc(); return getSubExpr()->getEndLoc(); } @@ -1051,7 +1060,7 @@ public: // Iterators child_range children() { - return child_range(&Op, Op ? &Op+1 : &Op); + return child_range(&Operand, Operand ? &Operand + 1 : &Operand); } }; @@ -1061,26 +1070,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 +1102,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 getBeginLoc() const LLVM_READONLY { return SourceLocation(); } - SourceLocation getEndLoc() 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 +1134,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 +1167,8 @@ public: return Field->getInClassInitializer(); } - SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } - SourceLocation getEndLoc() 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; @@ -2098,55 +2097,43 @@ public: /// 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,7 +2147,7 @@ public: /// be a pointer, return an invalid type. QualType getDestroyedType() const; - SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getBeginLoc() const { return CXXDeleteExprBits.Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return Argument->getEndLoc(); } @@ -2170,7 +2157,7 @@ public: } // 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. @@ -2472,8 +2459,6 @@ class ArrayTypeTraitExpr : public Expr { /// The type being queried. TypeSourceInfo *QueriedType = nullptr; - virtual void anchor(); - public: friend class ASTStmtReader; @@ -2491,8 +2476,6 @@ public: explicit ArrayTypeTraitExpr(EmptyShell Empty) : Expr(ArrayTypeTraitExprClass, Empty), ATT(0) {} - virtual ~ArrayTypeTraitExpr() = default; - SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParen; } @@ -3031,7 +3014,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. @@ -3044,8 +3027,6 @@ private: friend class ASTStmtReader; friend TrailingObjects; - Stmt *SubExpr; - ExprWithCleanups(EmptyShell, unsigned NumObjects); ExprWithCleanups(Expr *SubExpr, bool CleanupsHaveSideEffects, ArrayRef<CleanupObject> Objects); @@ -3070,17 +3051,10 @@ 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 getBeginLoc() const LLVM_READONLY { return SubExpr->getBeginLoc(); } diff --git a/include/clang/AST/FormatString.h b/include/clang/AST/FormatString.h new file mode 100644 index 0000000000..4a89c797b6 --- /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 7f01799421..a3c0cab379 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/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index 3a7b45767d..8befe9ae42 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/OSLog.h b/include/clang/AST/OSLog.h new file mode 100644 index 0000000000..2b21855e7a --- /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 6a2c806bb6..e93f7e2b3e 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -765,6 +765,179 @@ public: } }; +/// 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 @@ -5109,6 +5282,22 @@ class OMPClauseVisitor : 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 e2d65d8488..cd19091e31 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 ed6b97f9b9..0a4dc42898 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) {} /// 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 @@ -225,6 +224,12 @@ struct PrintingPolicy { /// When true, print the fully qualified name of function declarations. /// This is the opposite of SuppressScope and thus overrules it. unsigned FullyQualifiedName : 1; + + /// Whether to apply -fdebug-prefix-map to any file paths. + unsigned RemapFilePaths : 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/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 436425a9ee..eb582c7a7a 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. /// @@ -2199,6 +2209,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())); @@ -2868,6 +2880,30 @@ bool RecursiveASTVisitor<Derived>::VisitOMPUnifiedAddressClause( } 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 b4e0fd561e..23ac5af7ae 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,102 @@ 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; + }; + + 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 { @@ -207,24 +475,38 @@ protected: unsigned BasePathIsEmpty : 1; }; - 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 +521,97 @@ protected: unsigned ResultIndex : 32 - 8 - NumExprBits; }; - class OpaqueValueExprBitfields { - friend class OpaqueValueExpr; + //===--- C++ Expression bitfields classes ---===// + + 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 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 +632,20 @@ protected: unsigned NumArgs : 32 - 8 - 1 - NumExprBits; }; + 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; + }; + + //===--- C++ Coroutines TS bitfields classes ---===// + class CoawaitExprBitfields { friend class CoawaitExpr; @@ -293,24 +654,84 @@ 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 OpaqueValueExpr; + + unsigned : NumExprBits; + + /// The OVE is a unique semantic reference to its source expressio if this + /// bit is set to true. + unsigned IsUnique : 1; + }; + 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 + CXXBoolLiteralExprBitfields CXXBoolLiteralExprBits; + CXXNullPtrLiteralExprBitfields CXXNullPtrLiteralExprBits; + CXXThisExprBitfields CXXThisExprBits; + CXXThrowExprBitfields CXXThrowExprBits; + CXXDefaultArgExprBitfields CXXDefaultArgExprBits; + CXXDefaultInitExprBitfields CXXDefaultInitExprBits; + CXXDeleteExprBitfields CXXDeleteExprBits; TypeTraitExprBitfields TypeTraitExprBits; + ExprWithCleanupsBitfields ExprWithCleanupsBits; + + // C++ Coroutines TS expressions CoawaitExprBitfields CoawaitBits; + + // Obj-C Expressions + ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; + + // Clang Extensions + OpaqueValueExprBitfields OpaqueValueExprBits; }; public: @@ -380,7 +801,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!"); @@ -515,9 +936,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(); } @@ -572,33 +991,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 getBeginLoc() const LLVM_READONLY { return SemiLoc; } - SourceLocation getEndLoc() 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; @@ -615,7 +1026,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) {} @@ -628,8 +1040,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. @@ -655,7 +1068,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 { @@ -697,10 +1110,10 @@ public: return const_reverse_body_iterator(body_begin()); } - SourceLocation getBeginLoc() const LLVM_READONLY { return LBraceLoc; } - SourceLocation getEndLoc() 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) { @@ -718,36 +1131,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 getBeginLoc() const LLVM_READONLY { return KeywordLoc; } - SourceLocation getEndLoc() const LLVM_READONLY; + SourceLocation getBeginLoc() const { return getKeywordLoc(); } + inline SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == CaseStmtClass || @@ -755,52 +1172,137 @@ 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); } - Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); } - Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); } - Stmt *getSubStmt() { return SubExprs[SUBSTMT]; } + /// Get the location of the ... in a case statement of the form LHS ... RHS. + SourceLocation getEllipsisLoc() const { + return caseStmtIsGNURange() ? *getTrailingObjects<SourceLocation>() + : SourceLocation(); + } + + /// 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 getBeginLoc() const LLVM_READONLY { return KeywordLoc; } + void setSubStmt(Stmt *S) { + getTrailingObjects<Stmt *>()[subStmtOffset()] = S; + } + SourceLocation getBeginLoc() const { return getKeywordLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { // Handle deeply nested case statements with iteration instead of recursion. const CaseStmt *CS = this; @@ -816,16 +1318,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) @@ -835,12 +1339,10 @@ 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 getBeginLoc() const LLVM_READONLY { return KeywordLoc; } + SourceLocation getBeginLoc() const { return getKeywordLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return SubStmt->getEndLoc(); } @@ -850,48 +1352,57 @@ public: } // Iterators - child_range children() { return child_range(&SubStmt, &SubStmt+1); } + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } }; -inline SourceLocation SwitchCase::getEndLoc() const { +SourceLocation SwitchCase::getEndLoc() const { if (const auto *CS = dyn_cast<CaseStmt>(this)) return CS->getEndLoc(); - return cast<DefaultStmt>(this)->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 getBeginLoc() const LLVM_READONLY { return IdentLoc; } - SourceLocation getEndLoc() const LLVM_READONLY { - return SubStmt->getEndLoc(); - } + 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; @@ -909,17 +1420,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); } @@ -930,23 +1443,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 getBeginLoc() const LLVM_READONLY { return AttrLoc; } - SourceLocation getEndLoc() const LLVM_READONLY { - return SubStmt->getEndLoc(); - } + SourceLocation getBeginLoc() const { return getAttrLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { return SubStmt->getEndLoc();} child_range children() { return child_range(&SubStmt, &SubStmt + 1); } @@ -956,21 +1467,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; - SourceLocation IfLoc; - SourceLocation ElseLoc; + // 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; } + + /// 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); + + /// 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); + } - /// Build an empty if/then/else statement - explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) {} + 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. /// @@ -980,52 +1587,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; + } - SourceLocation getIfLoc() const { return IfLoc; } - void setIfLoc(SourceLocation L) { IfLoc = L; } - SourceLocation getElseLoc() const { return ElseLoc; } - void setElseLoc(SourceLocation L) { ElseLoc = L; } + 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 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 getBeginLoc() const LLVM_READONLY { return IfLoc; } - + SourceLocation getBeginLoc() const { return getIfLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { - if (SubExprs[ELSE]) - return SubExprs[ELSE]->getEndLoc(); - else - return SubExprs[THEN]->getEndLoc(); + 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) { @@ -1034,22 +1666,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; + + /// Points to a linked list of case and default statements. + SwitchCase *FirstCase; + + // 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); - // 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; + /// Build a empty switch statement. + explicit SwitchStmt(EmptyShell Empty, bool HasInit, bool HasVar); public: - SwitchStmt(const ASTContext &C, Stmt *Init, VarDecl *Var, Expr *cond); + /// Create a switch statement. + static SwitchStmt *Create(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, + Expr *Cond); - /// Build a empty switch statement. - explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) {} + /// 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. /// @@ -1060,64 +1772,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 getBeginLoc() const LLVM_READONLY { return SwitchLoc; } + bool isAllEnumCasesCovered() const { + return SwitchStmtBits.AllEnumCasesCovered; + } + SourceLocation getBeginLoc() const { return getSwitchLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { - return SubExprs[BODY] ? SubExprs[BODY]->getEndLoc() - : SubExprs[COND]->getEndLoc(); + 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) { @@ -1126,17 +1843,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. /// @@ -1146,29 +1921,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 getBeginLoc() const LLVM_READONLY { return WhileLoc; } + SourceLocation getWhileLoc() const { return WhileStmtBits.WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileStmtBits.WhileLoc = L; } + SourceLocation getBeginLoc() const { return getWhileLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { - return SubExprs[BODY]->getEndLoc(); + return getBody()->getEndLoc(); } static bool classof(const Stmt *T) { @@ -1177,46 +1958,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 getBeginLoc() const LLVM_READONLY { return DoLoc; } - SourceLocation getEndLoc() 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; @@ -1224,7 +2010,7 @@ public: // Iterators child_range children() { - return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + return child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; @@ -1232,7 +2018,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; @@ -1278,18 +2063,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 getBeginLoc() const LLVM_READONLY { return ForLoc; } - - SourceLocation getEndLoc() const LLVM_READONLY { - return SubExprs[BODY]->getEndLoc(); - } + SourceLocation getBeginLoc() const { return getForLoc(); } + SourceLocation getEndLoc() const { return getBody()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ForStmtClass; @@ -1304,12 +2086,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) {} @@ -1317,13 +2100,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 getBeginLoc() const LLVM_READONLY { return GotoLoc; } - SourceLocation getEndLoc() 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; @@ -1337,37 +2120,39 @@ 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 getBeginLoc() const LLVM_READONLY { return GotoLoc; } + SourceLocation getBeginLoc() const { return getGotoLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return Target->getEndLoc(); } static bool classof(const Stmt *T) { @@ -1375,24 +2160,24 @@ public: } // 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 getBeginLoc() const LLVM_READONLY { return ContinueLoc; } - SourceLocation getEndLoc() 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; @@ -1406,22 +2191,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 getBeginLoc() const LLVM_READONLY { return BreakLoc; } - SourceLocation getEndLoc() 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; @@ -1441,40 +2223,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(). - ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate) - : Stmt(ReturnStmtClass), RetLoc(RL), RetExpr((Stmt *)E), - NRVOCandidate(NRVOCandidate) {} + /// True if this ReturnStmt has storage for an NRVO candidate. + bool hasNRVOCandidate() const { return ReturnStmtBits.HasNRVOCandidate; } - /// Build an empty return expression. - explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) {} + unsigned numTrailingObjects(OverloadToken<const VarDecl *>) const { + return hasNRVOCandidate(); + } - const Expr *getRetValue() const; - Expr *getRetValue(); - void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt*>(E); } + /// Build a return statement. + ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate); - SourceLocation getReturnLoc() const { return RetLoc; } - void setReturnLoc(SourceLocation L) { RetLoc = L; } + /// 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); + + /// 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 getBeginLoc() const LLVM_READONLY { return RetLoc; } + SourceLocation getReturnLoc() const { return ReturnStmtBits.RetLoc; } + void setReturnLoc(SourceLocation L) { ReturnStmtBits.RetLoc = L; } + SourceLocation getBeginLoc() const { return getReturnLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { - return RetExpr ? RetExpr->getEndLoc() : RetLoc; + return RetExpr ? RetExpr->getEndLoc() : getReturnLoc(); } static bool classof(const Stmt *T) { @@ -1483,7 +2293,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()); } }; diff --git a/include/clang/AST/StmtDataCollectors.td b/include/clang/AST/StmtDataCollectors.td index e1929fe30b..90ca080273 100644 --- a/include/clang/AST/StmtDataCollectors.td +++ b/include/clang/AST/StmtDataCollectors.td @@ -27,7 +27,7 @@ class ExpressionTraitExpr { } class PredefinedExpr { code Code = [{ - addData(S->getIdentType()); + addData(S->getIdentKind()); }]; } class TypeTraitExpr { diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h index 170c78cf6b..d1eedd62b3 100644 --- a/include/clang/AST/StmtOpenMP.h +++ b/include/clang/AST/StmtOpenMP.h @@ -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 bbfffe8186..ea40e04973 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,18 +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...> {}; +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/TextNodeDumper.h b/include/clang/AST/TextNodeDumper.h new file mode 100644 index 0000000000..5a1dbb40fa --- /dev/null +++ b/include/clang/AST/TextNodeDumper.h @@ -0,0 +1,87 @@ +//===--- 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/CommentCommandTraits.h" +#include "clang/AST/CommentVisitor.h" +#include "clang/AST/ExprCXX.h" + +namespace clang { + +class TextNodeDumper + : public comments::ConstCommentVisitor<TextNodeDumper, void, + const comments::FullComment *> { + 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 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 dumpCXXTemporary(const CXXTemporary *Temporary); + + 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 *); +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_TEXTNODEDUMPER_H diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 28cfa00789..5b69570aab 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -256,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; @@ -1502,6 +1498,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; @@ -1512,18 +1511,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 { @@ -2025,6 +2044,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 @@ -2045,7 +2071,8 @@ public: STK_Integral, STK_Floating, STK_IntegralComplex, - STK_FloatingComplex + STK_FloatingComplex, + STK_FixedPoint }; /// Given that this is a scalar type, classify it. @@ -2371,6 +2398,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 @@ -3331,6 +3361,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. /// @@ -3465,6 +3581,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, @@ -3477,7 +3609,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; } @@ -3492,9 +3626,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. @@ -3544,104 +3683,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; @@ -3665,31 +3765,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. @@ -3705,88 +3828,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]; } @@ -3800,7 +3906,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(); @@ -3812,20 +3918,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 { @@ -3844,16 +3948,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 @@ -3864,7 +3978,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 @@ -3874,7 +3988,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 @@ -3885,11 +3999,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. @@ -3899,9 +4013,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 { @@ -3916,11 +4036,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 *; @@ -3930,22 +4050,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()); } @@ -3955,27 +4076,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; } @@ -4808,7 +4929,9 @@ public: 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); @@ -6359,9 +6482,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 { |